Как смоделировать метод с функциональными аргументами в Scala? - PullRequest
20 голосов
/ 28 января 2010

Я пытаюсь смоделировать вызов метода, который принимает аргумент call-by-name:

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)
      }
   }
}

Меня в первую очередь интересует Mockito, так как это то, что я использую, но я быинтересно узнать, способен ли какой-либо из основных фальшивых фреймворков на такого рода тестирование.Тест не выполняется во время выполнения в строке verify, с ошибкой типа

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)  

Если я правильно понимаю ситуацию, компилятор неявно переносит t внулевая функция, которая возвращает t.Затем фиктивная среда сравнивает эту функцию с той, которая создается в тестовом коде, что эквивалентно, но не equals().

Мой случай - относительно простая версия проблемы, но я думаю, что это будетпроблема с любой функцией высшего порядка.

Ответы [ 3 ]

10 голосов
/ 29 января 2010

Это выглядит ужасно, но, надеюсь, поможет вам найти хорошее решение:

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 голос
/ 01 февраля 2010

Эта проблема, по-видимому, специфична для вызовов по именам, поскольку в обычных функциях более высокого порядка вы можете сопоставить явный объект FunctionX:

verify (соавтор) .somethingElse (any (Function2 [String, Thing]))

в случае с именем по имени, завершение аргумента в Function0 выполняется неявно, и ответ Алексея показывает, как вызвать mock с явным параметром.

Вы могли бы написать что-то похожее на вашу собственную проверку, которая будет применять аргументы, захваченные mockito.

Mockito внутренне записывает вызовы и их аргументы, например: http://code.google.com/p/mockito/source/browse/trunk/src/org/mockito/internal/matchers/CapturingMatcher.java

0 голосов
/ 03 июня 2013

Вы можете попробовать specs2 . В specs2 мы «угнали» класс Mockito Invocation для учета параметров по имени:

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

byname.call(10)
there was one(byname).call(10)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...