2010-01-28 34 views
19

Tôi đang cố gắng để thử một phương pháp gọi là có một đối số gọi-by-name:Làm thế nào để giả lập một phương thức với các đối số chức năng trong Scala?

import org.scalatest.WordSpec 
import org.scalatest.mock.MockitoSugar 
import org.mockito.Mockito._ 
import org.junit.runner.RunWith 
import org.scalatest.junit.JUnitRunner 

trait Collaborator { 
    def doSomething(t: => Thing) 
} 

trait Thing 

@RunWith(classOf[JUnitRunner]) 
class Test extends WordSpec with MockitoSugar { 
    "The subject under test" should { 
     "call the collaborator" in { 
     // setup 
     val m = mock[Collaborator] 
     val t = mock[Thing] 

     // test code: this would actually be invoked by the SUT 
     m.doSomething(t) 

     // verify the call 
     verify(m).doSomething(t) 
     } 
    } 
} 

tôi chủ yếu quan tâm đến việc Mockito vì đó là những gì tôi đang sử dụng, nhưng tôi muốn được quan tâm để xem liệu bất kỳ khung mock chính nào có khả năng thử nghiệm kiểu này. Các thử nghiệm thất bại khi chạy trên dòng verify, với một lỗi như

Argument(s) are different! Wanted: 
collaborator.doSomething( 
    ($anonfun$apply$3) <function> 
); 
-> at Test$$anonfun$1$$anonfun$apply$1.apply(Test.scala:27) 
Actual invocation has different arguments: 
collaborator.doSomething( 
    ($anonfun$apply$2) <function> 
); 
-> at Test$$anonfun$1$$anonfun$apply$1.apply(Test.scala:24) 

Nếu tôi hiểu tình hình một cách chính xác, trình biên dịch được ngầm gói t trong một chức năng nullary trả t. Khung giả lập sau đó so sánh hàm đó với hàm được tạo trong mã thử nghiệm, tương đương nhưng không phải là equals().

Trường hợp của tôi là một phiên bản tương đối đơn giản của vấn đề, nhưng tôi nghĩ đây sẽ là vấn đề với bất kỳ chức năng bậc cao nào.

+3

Tôi không hiểu điều này liên quan đến iPad của Apple như thế nào. –

+0

Bạn có thể mô tả cách nó không hoạt động rõ ràng hơn hoặc bao gồm một số mã thử nghiệm hay không. Thật khó để biết những gì đang xảy ra ở đây chỉ với xác minh được hiển thị. –

+0

Tôi đã thực hiện các ví dụ runnable như bằng văn bản và bao gồm sản lượng thực tế liên quan đến sự thất bại. –

Trả lời

9

này trông xấu xí, nhưng hy vọng nó có thể giúp bạn tìm giải pháp tốt:

import org.scalatest.mock.MockitoSugar 
import org.mockito.Mockito._ 

trait Collaborator { 
    def doSomething(t: => Thing) 
} 

trait Thing 

new MockitoSugar { 
    // setup 
    val m = mock[Collaborator] 
    val t = mock[Thing] 

    m.doSomething(t) 

    classOf[Collaborator].getMethod("doSomething", classOf[Function0[_]]).invoke(
     verify(m), 
     new Function0[Thing] { 
      def apply() = null 
      override def equals(o: Any): Boolean = t == o.asInstanceOf[Function0[Thing]].apply() 
     }) 
} 
1

Vấn đề này dường như được cụ thể cho từng tên invocations vì trong các chức năng bậc cao thường xuyên bạn có thể kết hợp chống lại các FunctionX rõ ràng đối tượng:

xác minh (cộng tác viên) .somethingElse (bất kỳ (Function2 [string, Thing]))

trong từng tên trường hợp vỏ bọc của đối số vào một Function0 được thực hiện ngầm và Alexey của câu trả lời cho thấy cách để gọi giả lập với một tham số rõ ràng.

Bạn có thể viết một cái gì đó giống như xác minh của riêng bạn mà sẽ áp dụng các đối số được bắt bởi mockito.

Mockito nội bộ hồ sơ gọi và lập luận của mình với ví dụ .: http://code.google.com/p/mockito/source/browse/trunk/src/org/mockito/internal/matchers/CapturingMatcher.java

+0

Điều này không hoạt động, vì hàm này dự kiến ​​một tham số gọi theo tên của kiểu Thing (: => Thing), không phải là kiểu giống như Function2 [String, Thing] (: String => Thing). Cần có loại có mức độ cao hơn để nhập các tham số theo từng tên để sử dụng đối sánh. – Woodz

0

Bạn có thể thử specs2. Trong thông số 2, chúng tôi "chiếm đoạt" lớp Mockito Invocation để tính toán các tham số byname:

trait ByName { def call(i: =>Int) = i } 
val byname = mock[ByName] 

byname.call(10) 
there was one(byname).call(10) 
+0

Xin chào Eric, tôi đã sao chép đoạn mã đó vào thông số kỹ thuật ứng dụng Play 2.2.3 mới và nó vẫn không thành công. Tôi đang sử dụng một lớp 'mutable.Specification với lớp thử nghiệm Mockito' đơn giản,' specs2_2.10-2.1.1' và 'mockito-core-1.9.5' (được khai báo rõ ràng trong' build.sbt', đảm bảo rằng specs2 được khai báo trước mockito) Bất kỳ đầu mối nào tại sao nó vẫn thất bại? – jmelanson

+0

Bạn cần đảm bảo rằng lọ thông số kỹ thuật đến trước bình Mockito trên đường dẫn lớp. – Eric

+0

Bất kỳ gợi ý nào về điều đó với SBT? Tôi đã thử thay đổi thứ tự khai báo. – jmelanson

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