如果您可以更改代码
Worker
,您可以将其更改为仍然允许它作为对象,并允许通过
implicit
具有默认定义。这是一个解决方案,我甚至不知道这对你来说是否可行,但这里是:
case class MyObj(id:Long)
trait DatabaseService{
def getById(id:Long):Option[MyObj] = {
//some impl here...
}
}
object DatabaseService extends DatabaseService
object Worker{
def doSomething(id:Long)(implicit dbService:DatabaseService = DatabaseService):Option[MyObj] = {
dbService.getById(id)
}
}
因此,我们建立了一个具有
getById
方法然后我们添加一个
object
该特性的impl作为要在代码中使用的单实例。这是一个很好的模式,可以用来嘲笑以前只定义为
对象
。然后,我们
工人
接受
含蓄的
DatabaseService
(特征),并将其默认值设置为
对象
数据库服务
因此,常规使用不必担心满足该要求。然后我们可以这样测试:
class WorkerUnitSpec extends Specification with Mockito{
trait scoping extends Scope{
implicit val mockDb = mock[DatabaseService]
}
"Calling doSomething on Worker" should{
"pass the call along to the implicit dbService and return rhe result" in new scoping{
mockDb.getById(123L) returns Some(MyObj(123))
Worker.doSomething(123) must beSome(MyObj(123))
}
}
在这里,在我的范围内,我做了一个含蓄的嘲讽
数据库服务
可用,将取代默认值
数据库服务
上
doSomething
用于我的测试目的。一旦你做到了这一点,你就可以开始模仿和测试了。
使现代化
如果你不想采用隐式方法,你可以重新定义
工人
像这样:
abstract class Worker(dbService:DatabaseService){
def doSomething(id:Long):Option[MyObj] = {
dbService.getById(id)
}
}
object Worker extends Worker(DatabaseService)
然后这样测试:
class WorkerUnitSpec extends Specification with Mockito{
trait scoping extends Scope{
val mockDb = mock[DatabaseService]
val testWorker = new Worker(mockDb){}
}
"Calling doSomething on Worker" should{
"pass the call along to the implicit dbService and return rhe result" in new scoping{
mockDb.getById(123L) returns Some(MyObj(123))
testWorker.doSomething(123) must beSome(MyObj(123))
}
}
}
通过这种方式,您可以在抽象中定义所有重要的逻辑
工人
类,这是您测试的重点。您提供了一个单例
工人
通过代码中为方便而使用的对象。有了抽象类,我们就可以使用构造函数参数来指定要使用的数据库服务impl。这在语义上与前面的解决方案相同,但它更清晰,因为您不需要每个方法上的隐式。