前提条件:我正在使用最新版本的Play!框架和Java版本(而不是Scala)。
当创建用户时,我需要将消息发布到消息队列,并且我希望测试这种行为。我的问题在于如何使其易于测试。
控制器方法
在其他框架中,我会在控制器中使用构造函数注入并在我的测试中传递模拟队列;但是,对于Play!来说,控制器是静态的,这意味着我无法在我的测试中执行new MyController(mockedQueue)
。
我可以使用Google Guice并在我的控制器中的静态字段上放置一个@Inject
注释,但是这对我来说并不好,因为它要么意味着我必须将该字段公开以便在测试中替换它,要么我必须在我的测试中使用容器。我更喜欢使用构造函数注入,但是Play!似乎没有提供这个功能。
模型方法
通常说,您的逻辑应该在您的模型中,而不是在您的控制器中。这很有道理;但是,在这里我们不是在Ruby中,让您的实体与外部服务(电子邮件,消息队列等)交互比在动态环境中要容易测试得多,您可以随意将MessageQueue
静态调用替换为模拟实例。
如果我让我的实体调用队列,那怎么测试呢?
当然,如果我进行端到端的集成测试,则这两种情况都是不必要的,但我宁愿不需要为了运行测试而启动消息队列或SMTP服务器。
所以我的问题是:如何设计我的Play!控制器和/或模型以便于测试与外部服务的交互?
ServiceFactory
方法的一个 潜在 问题是字段何时被初始化;由于它是静态字段,因此在您有机会替换实例之前,初始化程序可能会通过getInstance
调用。只是随便想想,没有实际验证过这一点。 - James GregorygetInstance
返回的任何值之前就已经被初始化的情况。通常你无法控制静态初始化器的执行时间,因此它可能在你的测试设置发生之前就已经被执行了。 - James GregorygetInstance()
方法,它都将始终返回相同的单例实例(即ServiceFactory实例)。我们正在配置ServiceFactory,以便我们可以替换从getQueueService()
方法返回的值。 - Andre RodriguesServiceFactory
有效地返回单例似乎有点奇怪,但我可以理解这样做的理由。谢谢,是我的错误。 - James GregoryServiceFactory
并不需要为其生产的每个服务返回单例实例。只是在这个例子中,ServiceFactory
本身是一个单例。getInstance()
方法提供了访问ServiceFactory
实例的方式。 - Andre Rodrigues