我正在使用 scalamock 来模拟这个类:
class HttpService {
def post[In, Out]
(url: String, payload: In)
(implicit encoder: Encoder[In], decoder: Decoder[Out])
: Future[Out] = ...
...
}
...所以我的测试类有一个这样使用的模拟:
val httpService = mock[HttpService]
(httpService.post[FormattedMessage, Unit](_ : String, _ : FormattedMessage) (_ : Encoder[FormattedMessage], _: Decoder[Unit]))
.expects("http://example.com/whatever",*, *, *)
.returning(Future.successful(()))
显然我必须编写整个模拟函数签名。如果我只将下划线放在签名中,而没有相应的类型,我会得到这样的错误:
[error] missing parameter type for expanded function ((x$1: <error>, x$2, x$3, x$4) => httpService.post[FormattedMessage, Unit](x$1, x$2)(x$3, x$4))
[error] (httpService.post[FormattedMessage, Unit](_, _) (_, _))
^
我不喜欢这段代码的地方是,在测试中的多个地方都使用了模拟期望,并且这个丑陋的签名在所有地方重复,但具有不同的 In/Out 类型参数和期望。
所以我想我会写一堂课
class HttpServiceMock extends MockFactory {
val instance = mock[HttpService]
def post[In, Out] = instance.post[In, Out](_ : String, _ : In) (_ : Encoder[In], _: Decoder[Out])
}
...并像这样使用它:
val httpService = new HttpServiceMock()
...
httpService.post[FormattedMessage, Unit]
.expects("http://example.com/whatever",*, *, *)
.returning(Future.successful(()))
...编译得很好,但是当我运行测试时,出现以下错误:
java.lang.NoSuchMethodException: com.myapp.test.tools.HttpServiceMock.mock$post$0()
at java.lang.Class.getMethod(Class.java:1786)
at com.myapp.controllers.SlackControllerSpec.$anonfun$new$3(SlackControllerSpec.scala:160)
at org.scalatest.OutcomeOf.outcomeOf(OutcomeOf.scala:85)
at org.scalatest.OutcomeOf.outcomeOf$(OutcomeOf.scala:83)
at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
at org.scalatest.Transformer.apply(Transformer.scala:22)
at org.scalatest.Transformer.apply(Transformer.scala:20)
at org.scalatest.WordSpecLike$$anon$1.apply(WordSpecLike.scala:1078)
at org.scalatest.TestSuite.withFixture(TestSuite.scala:196)
at org.scalatest.TestSuite.withFixture$(TestSuite.scala:195)
我该如何解决这个错误?还有其他方法可以避免一遍又一遍地重写模拟函数签名吗?
更新:最后模拟看起来像这样:
trait HttpServiceMock extends MockFactory {
object httpService {
val instance = mock[HttpService]
def post[In, Out] = toMockFunction4(instance.post[In, Out](_: String, _: In)(_: Encoder[In], _: Decoder[Out]))
}
}