2017-04-24 39 views
0

我有一個函數在斯卡拉如下如何嘲弄與視圖邊界的函數作爲參數

object MyService extends MyTrait {  
    def myMethod[T <% InvokableBuilder[MyClass]](builder: T): MyResponse = { 
    //do something 
    } 
} 

我想使用類似的Mockito以下

val mockService = mock[MyTrait] 

doReturn(info).when(mockService).myMethod(any()) 

我嘲笑這個功能得到以下錯誤,雖然我只有一個參數在功能

org.mockito.exceptions.misusing.InvalidUseOfMatchersException:無效的使用argume nt matchers! [信息] 2點的匹配預期,1記錄:

回答

1

您的問題是:Scala是的Java。

您的隱含假設是:「那個小scala方法會被轉換成Java中類似的東西;因此我可以簡單地使用mockito來處理這個問題。

錯誤。您正在創建一個scala 對象這裏定義;如果我沒有記錯, 對象 in scala ...在Java中轉換爲static(例如,請參閱here)。

因此,乍一看,您可能需要轉向PowerMock(ito) JMockit以模擬那些靜態元素。 (以及我通常的警告:不要使用PowerMock;因爲嘲弄靜態的東西是一個想法不好的)。正如Philipp M在他的評論中指出的那樣:嘲諷靜態確實被認爲是不好的做法。你應該在這裏嘲笑事物的「特質」一面。

所以真正的答案是:你必須知道你在做什麼。 Mockito寫作爲java。你不能假設你在scala中寫下的任何東西,以及像Java那樣「看起來似乎」的東西都可以很容易地映射到Mockito正在開展的工作。

爲了真正理解發生了什麼;你應該首先看看scala編譯器在你的案例中創建的類文件;檢查方法簽名;併爲自己思考:「如果我必須在java源代碼中調用該方法,那麼我該怎麼做?」並從那裏工作。

+0

我同意這個答案的前半部分 - 斯卡拉'object's是單身,並應受到同樣的對待。 我不喜歡使用PowerMock解決這個問題,並在測試執行過程中操作字節碼的想法。在我看來,讓'object'實現一個'trait'就好像你已經擁有了,並且嘲笑這個特性。 –

+0

對不起,我的回覆是一半寫入,然後輸入提交:) –

+0

明白了...並將其添加到答案。我完全同意。 – GhostCat

0

我改變了你的//做些什麼?所以它會編譯,然後打印的代碼在語法分析器階段結束:

$scalac MyService.scala -Xprint:parser 
[[syntax trees at end of     parser]] // MyService.scala 
package <empty> { 
    object MyService extends MyTrait { 
    def <init>() = { 
     super.<init>(); 
    () 
    }; 
    def myMethod[T](builder: T)(implicit evidence$1:_root_.scala.Function1[T,InvokableBuilder[MyClass]]): MyResponse = $qmark$qmark$qmark 
    } 
} 

正如你所看到的,myMethod的有第二個參數列表由於綁定您的視圖。 我不確定你會如何嘲笑Mockito,但我建議嘗試ScalaMock。

注意:視圖邊界不推薦 - 我建議用一個隱式參數替換它們(請參閱scalac解析器如何執行上述操作)。

稍長的例子:

import org.scalamock.scalatest.MockFactory 
import org.scalatest.FlatSpec 

import scala.language.implicitConversions 

class FooTest extends FlatSpec with MockFactory { 

    trait MyTrait { 
    def myMethod[T](builder: T)(implicit ev$1: T => InvokableBuilder[MyClass]): MyResponse 
    } 

    trait InvokableBuilder[T] 

    class MyClass 

    class MyResponse 

    class Foo 

    object MyService extends MyTrait { 
    def myMethod[T](builder: T)(implicit ev$1: T => InvokableBuilder[MyClass]): MyResponse = { 
     //do something 
     ??? 
    } 
    } 

    behavior of "Foo" 

    it should "foo" in { 
    val x = mock[MyTrait] 

    implicit val fooConvert: Foo => InvokableBuilder[MyClass] = ??? 
    (x.myMethod(_: Foo)).expects(*).once() 
    } 

}