Play/Scala 将对象注入控制器进行测试

Play/Scala injecting Object into controller for testing

我看到了这个帖子我有类似的问题,但我的问题是如何注入对象来测试控制器。

控制器

@Singleton
class ExampleCtrl @Inject() (dao: TestDAO) extends Controller {
//code here
   def testMethod = Action { request =>
       dao.exampleMethod()
       Ok(Json.obj("test" -> "test")
   }
 }

DAO

class TestDAO @Inject()(protected val provider: DatabaseConfigProvider){
  def exampleMethod()
}

测试

class ExampleCtrlSpec extends PlaySpec with MockitoSugar {
  val service = mock[TestDAO]//problem on injecting DatabaseConfigProvider
  val controller = new ExampleCtrl(service)
  //service has null value for DatabaseConfigProvider properties

  "testMethod()" should {
    "return JSON" in {
      when(service.exampleMethod) thenReturn "json data"
      val result: Future[Result] =
      controller.testMethod().apply(FakeRequest())
      .withJsonBody(JSON.json("""[{"test":"test"}]"""))
      contentAsString(result) mustEqual """[{"test":"test"}]"""
    }
  }
}

所以我尝试重现该问题,但在修复了 IDE 代码识别的一些问题(例如缺少括号)后,测试通过了。

problem on injecting DatabaseConfigProvider

我在这里没有看到任何问题,因为代码正在通过。从编码人员的角度来看,mock[TestDAO] 实际上并没有实例化一个真正的 TestDAO,但它创建了一些看起来像一个(接口方面)的东西,但实际上并不包含任何你想要的逻辑里面写着TestDAO。因此,模拟对象也不需要注入DatabaseConfigProvider

service has null value for DatabaseConfigProvider properties

因为服务(您的模拟 TestDAO)是一个模拟,所以这不是问题,因为没有逻辑会使用它。您的模拟实际执行的唯一逻辑在这里:

when(service.exampleMethod) thenReturn "json data"

使用模拟时,您需要编写您希望它们在测试中展示的行为,就像您在上面的代码片段中所做的那样。

如果您想 运行 任何 DatabaseConfigProvider 方法,也许您需要:

  • 直接创建一个(例如val myProvider = [new] DatabaseConfigProvider(...)),
  • 将 mocking 移出一层,这样你就有了一个真正的控制器,一个真正的 TestDAO 和一个 mock DatabaseConfigProvider(类似于 val controller = new ExampleCtrl(new TestDAO(mock[DatabaseConfigProvider]))),或者
  • 一起编写不同类型的测试。

我通过以下方式解决了问题。

def testDAO (implicit app: Application) = {
    val app2testDAO = Application.instanceCache[TestDAO ]
    app2testDAO(app)
}
val controller = new ExampleCtrl(testDAO)