2011-10-23 52 views
6

Tôi bắt đầu học Scala ngày hôm qua, vì vậy tôi khá mới với nó. Một điều tôi muốn làm khi học một ngôn ngữ mới là cố gắng tạo ra một lib vi-TDD.Scala - Làm cách nào để thực hiện phương pháp "assertThrows"?

Đây là những gì tôi có cho đến nay:

def assert(condition: Boolean, message: String) { 
    if(!condition){ throw new AssertionError(message) } 
} 

def assertThrows[E](f: => Unit) { 
    try { 
    f 
    } catch { 
    case e: E => { return } 
    case _: Exception => { } 
    } 
    throw new AssertionError("Expected error of type " + classOf[E]) 
} 

Mã này cho assert công trình tốt, nhưng tôi đang gặp hai vấn đề với assertThrows.

  • Dường như tôi không thể sử dụng E trên dòng cuối cùng. Dù tôi có làm gì đi nữa, tôi vẫn nhận được class type expected but E found error.
  • Nếu tôi loại bỏ E từ dòng cuối cùng (thay thế nó bằng throw new AssertionError("error expected"), ví dụ) Tôi có được điều này: warning: abstract type E in type pattern is unchecked since it is eliminated by erasure

Tôi nghĩ rằng hai vấn đề tôi đang gặp có liên quan với cách Scala (và có lẽ java) giao dịch với các loại trừu tượng và chúng được thực hiện như thế nào.

Làm cách nào để khắc phục assertThrows của tôi?

Điểm thưởng: là cách tôi chỉ định "loại khối" (f: => Unit) đúng không?

+1

Một câu hỏi tôi đã không lâu trước đây có thể trợ giúp: http://stackoverflow.com/questions/7699709/scala-expected-exception-snippet –

Trả lời

8

Máy ảo Java thực hiện Generics thông qua loại xóa, do đó bên trong cơ thể phương pháp JVM không thực sự biết bất cứ điều gì về loại E, vì vậy phương pháp AssertThrows này không thể làm việc theo cách bạn muốn. Bạn cần phải ngầm vượt qua một Manifest cho lớp ngoại lệ của bạn, như vậy:

def assertThrows[E](f: => Unit)(implicit eType:ClassManifest[E]) { 

Sau đó, bạn có thể sử dụng nó trong cơ thể để bắt ngoại lệ hoặc lấy tên lớp như vậy:

try { 
    f 
    } catch { 
    case e: Exception => 
     if (eType.erasure.isAssignableFrom(e.getClass)) 
     return; 
    } 
    throw new AssertionError("Expected error of type " + eType.erasure.getName) 
} 

Cảm ơn đến the Spring framework's AssertThrows class để chỉ cho tôi cách thực hiện việc này.

+0

Cảm ơn câu trả lời của bạn. Bạn có thể bao gồm một ví dụ về sử dụng không? Tôi không thể làm cho nó hoạt động được. – kikito

+0

Nevermind, tôi nhận được nó làm việc (thêm một câu trả lời). Tôi đang chỉnh sửa một lỗi đánh máy nhỏ trong câu trả lời của bạn và đánh dấu nó là chính xác. – kikito

0

Tôi có điều này nhờ làm việc để trả lời Ken:

class AssertException(msg: String) extends Exception(msg: String) 

def assertThrows[E](f: => Unit)(implicit eType:ClassManifest[E]) { 
    try{ 
    f 
    } catch { 
    case e: Exception => 
    if(eType.erasure.isAssignableFrom(e.getClass)) { return } 
    } 
    throw new AssertException("Expected error of type " + eType.erasure.getName) 
} 

/* examples of usage */ 

assertThrows[NullPointerException]{ throw new NullPointerException() } // ok 
assertThrows[AssertException] { assertThrows[Exception]{ } } // ok! 

Cảm ơn rất nhiều!

+0

Thực sự tuyệt vời !! –

Các vấn đề liên quan