这是在Play框架的上下文中。我有一个实例化验证器的控制器。验证器具有验证方法。控制器有一个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()被调用了,因此测试失败。
我该如何解决这个问题呢?
发布于 2015-02-27 08:56:41
问题是在你的最后一行:
EntityController.putEntity(payload)您实际上是在调用EntityController上的静态方法,尽管您试图配置一个模拟Validator,但您从未有机会将其“注入”到控制器中。
在不了解如何实现控制器的情况下提出一个理想的解决方案可能有点困难,但在猜测中,您可能希望执行以下操作,以允许注入模拟的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中。
希望这篇文章能对你有所帮助,并为你阐明一些有效的单元测试思想。
https://stackoverflow.com/questions/28753267
复制相似问题