我的第一个问题question已得到回答,但发现了我遇到的另一个问题。这是场景。
示例代码(从上一个问题扩展)
一个模型:
case class User (first: String, last: String, enabled: Boolean)
组件定义:
trait DataProviderComponent {
def find[T: ClassTag](id: Int): Try[T]
def update[T](data: T): Try[T]
}
具体的组件实现之一(更新的实现):
class DbProvider extends DataProviderComponent {
override def find[T: ClassTag](id: Int): Try[T] = {
Try {
val gson = new Gson()
val testJson = """{"first": "doe", "last": "jane", "enabled": false}"""
gson.fromJson(testJson, implicitly[ClassTag[T]].runtimeClass).asInstanceOf[T]
}
}
override def update[T](data: T): Try[T] = ???
}
组件impl在系统中某处的隐式使用:
implicit val provider = new DbProvider()
class UserRepsitory(implicit provider: DataProviderComponent) {
def userEnabled(id: Int): Boolean = {
val user = provider.find[User](id)
user.isSuccess && user.get.enabled
}
}
单元Test1,尝试模拟提供程序以隔离存储库测试。这不起作用,运行测试时将引发以下执行。我希望这是因为使用了ClassTag,因为当我创建另一个不使用ClassTag的示例时,它可以正常工作。
org.scalamock.MockFunction2无法转换为org.scalamock.MockFunction1
java.lang.ClassCastException:org.scalamock.MockFunction2无法转换为org.scalamock.MockFunction1
class UserRepository$Test1 extends FunSuite with Matchers with MockFactory {
test("invalid data request should return false") {
implicit val mockProvider: DataProviderComponent = mock[DataProviderComponent]
(mockProvider.find[User] _).expects(13).returns(Failure[User](new Exception("Failed!")))
val repo = new UserRepsitory()
repo.userEnabled(13) should be (false)
}
}
单元Test2确实可以工作,但是很难维护,并且需要更多代码:
class UserRepository$Test2 extends FunSuite with Matchers with MockFactory {
test("invalid data request should return false") {
class FakeProvider extends DataProviderComponent {
override def find[T:ClassTag](id: Int): Try[T] = Failure[T](new Exception("Failed!"))
override def update[T](data: T): Try[T] = ???
}
implicit val provider = new FakeProvider()
val repo = new UserRepsitory()
repo.userEnabled(13) should be (false)
}
}
单元Test3确实可以工作,但是-仅用于测试ClassTag实现:
class UserRepository$Test3 extends FunSuite with Matchers with MockFactory {
test("prove sut works") {
implicit val provider = new DbProvider()
val repo = new UserRepsitory()
val user = repo.userEnabled(13)
println(user.toString)
}
}
我使用ClassTag错误还是模拟无法正确模拟?
最佳答案
这类似于:ScalaMock User Guide: Mocking methods with implicit params-有一个隐式的ClassTag
参数,因此您必须说服
Scala编译器应将find[T](id:Int)(m: ClassTag[T])
转换为MockFunction2
以下代码可用于ScalaMock 3.2:
package com.paulbutcher.test.mock
import org.scalamock.scalatest.MockFactory
import org.scalatest.{ FlatSpec, ShouldMatchers }
import scala.reflect.ClassTag
import scala.util.{ Failure, Try }
case class User(first: String, last: String, enabled: Boolean)
trait DataProviderComponent {
def find[T: ClassTag](id: Int): Try[T]
def update[T](data: T): Try[T]
}
class UserRepsitory(implicit provider: DataProviderComponent) {
def userEnabled(id: Int): Boolean = {
val user = provider.find[User](id)
user.isSuccess && user.get.enabled
}
}
class ClassTagTest extends FlatSpec with ShouldMatchers with MockFactory {
behavior of "ScalaMock"
it should "handle mocking methods with class tags" in {
implicit val mockProvider: DataProviderComponent = mock[DataProviderComponent]
(mockProvider.find[User](_: Int)(_: ClassTag[User])).expects(13, *).returns(Failure[User](new Exception("Failed!")))
val repo = new UserRepsitory()
repo.userEnabled(13) should be(false)
}
}