将 Mockito 与 Specs2 结合使用,我模拟服务以验证它们的方法调用。
我的控制器是由 Spring 实例化的。这使我可以将其视为class 而不是object。 => 这对于使controller 可测试至关重要。举个例子:
@Controller
class MyController @Autowired()(val myServices: MyServices) extends Controller
要为控制器启用 Spring,您必须定义一个 Global 对象,作为 Play!文档说明:
object Global extends GlobalSettings {
val context = new ClassPathXmlApplicationContext("application-context.xml")
override def getControllerInstance[A](controllerClass: Class[A]): A = {
context.getBean(controllerClass)
}
}
我的单元测试不需要 Spring;我只是将合作者(模拟)传递给构造函数。
但是,关于呈现的模板,我只测试结果的类型(Ok、BadRequest、Redirection 等...)。
事实上,我注意到让我的测试详细扫描整个渲染模板(发送给它的参数等)并不容易,只需要单元测试。
因此,为了断言使用正确的参数调用了正确的模板,我相信我运行 Selenium 的验收测试或可能的功能测试(如果您愿意的话)会扫描整个预期结果。
2 - 来自服务的返回值被传递给正确的
模板的属性
这很容易检查..如何?通过信任编译器!更喜欢将一些自定义类型传递给您的模板,而不是简单的原语,例如:
phone: String 将变为:phone: Phone。 (一个简单的值对象)。
因此,不必担心以非预期的顺序将属性传递给您的模板(在单元测试或实际生产代码中)。编译器确实会发出警告。
这是我使用 specs2 进行的一项单元测试(简化)的示例:
(您会注意到包装器的使用:WithFreshMocks)。
这个case class 将允许在测试后刷新所有变量(在本例中为模拟)测试。
因此是重置模拟的好方法。
class MyControllerSpec extends Specification with Mockito {
def is =
"listAllCars should retrieve all cars" ! WithFreshMocks().listAllCarsShouldRetrieveAllCars
case class WithFreshMocks() {
val myServicesMock = mock[MyServices]
val myController = new MyController(myServicesMock)
def listAllCarsShouldRetrieveAllCars = {
val FakeGetRequest = FakeRequest() //fakeRequest needed by controller
mockListAllCarsAsReturningSomeCars()
val result = myController.listAllCars(FakeGetRequest).asInstanceOf[PlainResult] //passing fakeRequest to simulate a true request
assertOkResult(result).
and(there was one(myServicesMock).listAllCars()) //verify that there is one and only one call of listAllCars. If listAllCars would take any parameters that you expected to be called, you could have precise them.
}
private def mockListAllCarsAsReturningSomeCars() {
myServicesMock.listAllCars() returns List[Cars](Car("ferrari"), Car("porsche"))
}
private def assertOkResult(result: PlainResult) = result.header.status must_== 200
}