在Scala中使用Mockito和Spec2

时间:2015-02-26 21:39:48

标签: scala mockito

这是在Play框架的上下文中。我有一个实例化验证器的控制器。 Validator有验证方法。 Controller有一个方法putEnity(),它使用这个validate()验证它接收的有效负载。

对于控制器的单元测试,我想模拟调用Validator.validate()。 TestController看起来像这样

class EntityControllerTest extends FlatSpec with Mockito {
def testPutEntity() = {
  val payload = createPayload()
  val mockValidator = mock[Validator]
  when(mockValidator.validate(anyString, anyString)).thenReturn(EntityValidationResult(true, "Test"))                                            
  EntityController.putEntity(payload)
}

问题是,这个模拟调用没有被使用,但实际的validate()被调用,因此测试失败。

我该如何解决这个问题

1 个答案:

答案 0 :(得分:0)

问题在于你的最后一行:

EntityController.putEntity(payload)

你有效地在EntityController上调用了一个静态方法,尽管你试图配置一个模拟Validator,但你从来没有机会注入它#34;"进入控制器。

如果没有看到你如何实现你的控制器,建议一个理想的解决方案会有点困难,但猜测一下,你想要做类似以下的事情允许一个模拟的Validator被注入进行测试,但是其他一切都像之前一样工作。

我会逐步完成它(希望)让它更清晰:

第1步 - 使EntityController可实例化:

你可能有这样的事情:

object EntityController extends Controller {
   ...
   def putEntity = Action ...
   ..
}

替换为:

class EntityControl extends Controller {
   ...
   def putEntity = Action ...
   ...
}

object EntityController extends EntityControl

现在,您已经为自己提供了new具有与您的"生产相同的行为的能力"宾语。但我们需要能够在模拟验证器中替换......

第2步 - 要求EntityControl中的验证程序实例:

您的旧EntityController对象可能有这样的内容:

object EntityController extends Controller {
  val validator = new Validator(...)
  ...
}

这就是为什么你永远不会让你的模拟验证器参与其中。让我们将它作为构造函数参数注入,这样就不会忘记它:

class EntityControl(val validator:Validator) extends Controller {
   ...
}

object EntityController extends EntityControl(new Validator(...))

再次,我们的"生产" EntityController对象具有我们过去拥有的所有功能,但关键的区别在于我们已经暴露了"testing seam"以允许在需要时注入模拟。

第3步 - 注入并测试!

翻转到您的测试规范,并设置一个可测试的EntityControl实例

class EntityControllerTest extends FlatSpec with Mockito {

  def testPutEntity() = {
    val payload = createPayload()
    val mockValidator = mock[Validator]
    when(mockValidator.validate(anyString, anyString)).thenReturn(EntityValidationResult(true, "Test"))  

    val myTestableEC = new EntityControl(mockValidator)                                          
    myTestableEC.putEntity(payload)
}

在开发更多测试用例时,您可能希望将测试的设置和布线部分提取到合适的函数中,甚至是Specs2 Scope

希望这会有所帮助,并为您澄清一些有效的单元测试想法。