如何在 grails 服务中使用依赖注入有选择地设置属性以进行单元测试
编辑:请让我说清楚,我问的是如何在 Grails 中使用 Spring 依赖注入来做到这一点,而不是 Grails 的元类功能或 new()。
我有一个用于分析日志文件的 grails 服务。在服务中,我使用当前时间来做很多事情。对于单元测试,我有几个使用此服务解析的示例日志文件。显然,这些都有时间。
我希望我的服务在单元测试期间认为当前时间不超过示例日志文件中最后一个日志记录语句之后的几个小时。
所以,我愿意这样做:
class MyService {
def currentDate = { -> new Date() }
def doSomeStuff() {
// need to know when is "right now"
Date now = currentDate()
}
}
所以,我想要做的是注入 currentDate 或将其设置为其他硬编码时间,例如
currentDate = { -> new Date(1308619647140) }
是否没有办法用某些方法来做到这一点在我的单元测试中模拟什么方法?使用 Google Guice 这类事情非常简单,但我不知道如何在 Spring 中做到这一点。
令人非常沮丧的是,当我搜索“grails 依赖注入”时,我发现的都是示例
class SomeController {
// wow look how amazing this is, it's injected automatically!!
// isn't spring incredible OMG!
def myService
}
感觉所有向我展示的是我不必输入 new ...()
我在哪里告诉它当环境等于测试时,然后执行以下操作:
currentDate = { -> new Date(1308619647140) }
我只是在测试中手动设置此属性吗?
我不想创建一个“timeService”,因为考虑到我只想要 1 个微小的改变,这看起来很愚蠢。
EDIT: Please let me be clear, I'm asking how to do this in Grails using Spring Dependency Injection, and NOT Grails' metaclass functionality or new().
I have a grails service that is for analyzing log files. Inside the service I use the current time for lots of things. For unit testing I have several example log files that I parse with this service. These have times in them obviously.
I want my service, DURING UNIT TESTING to think that the current time is no more than a few hours after the last logging statement in my example log files.
So, I'm willing to this:
class MyService {
def currentDate = { -> new Date() }
def doSomeStuff() {
// need to know when is "right now"
Date now = currentDate()
}
}
So, what I want to be able to do is have currentDate injected or set to be some other HARDCODED time, like
currentDate = { -> new Date(1308619647140) }
Is there not a way to do this with some mockWhatever method inside my unit test? This kind of stuff was super easy with Google Guice, but I have no idea how to do it in Spring.
It's pretty frustrating that when I Google "grails dependency injection" all I find are examples of
class SomeController {
// wow look how amazing this is, it's injected automatically!!
// isn't spring incredible OMG!
def myService
}
It feels like all that's showing me is that I don't have to type new ...()
Where do I tell it that when environment equals test, then do this:
currentDate = { -> new Date(1308619647140) }
Am I just stuck setting this property manually in my test??
I would prefer not to have to create a "timeService" because this seems silly considering I just want 1 tiny change.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
Groovy 是一种动态语言,因此它几乎可以满足您的要求:
请记住,这只会修改
service
实例,而不是类。如果您需要修改类,则需要使用metaClass
。看看 这篇文章,作者:mrhaki。另一种选择是将当前日期作为
doSomeStuff()
的参数。这样您就不需要修改您的服务实例。Groovy is a dynamic language, and as such it allows you to do almost what you're asking for:
Keep in mind this only modifies the
service
instance, not the class. If you need to modify the class you'll need to work with themetaClass
. Take a look at this post by mrhaki.Another option would be to make the current date a parameter to
doSomeStuff()
. That way you wouldn't need to modify your service instance.谢谢你们的帮助。在这种情况下,我能想到的使用 Spring DI 的最佳解决方案是在
resources.groovy
中执行以下操作,这是我发现的两个解决方案:
1:如果我希望将 timeNowService 交换到各处进行测试:
2:如果我只想将此更改应用于此特定服务,我可以这样做:
无论哪种情况,我都会通过致电使用该服务
timeNowService.now()
。对我来说,一件奇怪且非常令人沮丧的事情是我无法做到这一点:
事实上,当我尝试时,我也有一个虚拟值,例如
dummy = 'hello 2'
然后myService 类本身的默认值dummy = 'hello'
。当我用其中设置的虚拟值执行第三个示例时,它默默地无法设置,显然 b/c timeNow 私下炸毁了一些东西。我很想知道是否有人可以解释为什么会失败。
感谢大家的帮助,很抱歉我不耐烦了......
Thanks for the help guys. The best solution I could come up with for using Spring DI in this case was to do the following in
resources.groovy
These are the two solutions I found:
1: If I want the timeNowService to be swapped for testing purposes everywhere:
2: I could do this if I only want this change to apply to this particular service:
In either case I would use the service by calling
timeNowService.now()
.The one strange, and very frustrating thing to me was that I could not do this:
In fact, when I tried that I also had a dummy value in there, like
dummy = 'hello 2'
and then a default value ofdummy = 'hello'
in the myService class itself. And when I did this 3rd example with the dummy value set in there as well, it silently failed to set, apparently b/c timeNow blew something up in private.I would be interested to know if anyone could explain why this fails.
Thanks for the help guys and sorry to be impatient...
由于 Groovy 是动态的,因此您可以从服务中删除 currentDate() 方法,并将其替换为适合您需要的方法。您可以在测试设置期间在运行时执行此操作。
在实例化 MyService 实例之前,请执行以下代码:
这样,您就可以在所有测试中获得一致的行为。
但是,如果您愿意,可以通过具有相同技巧的闭包来覆盖实例方法。
让我知道进展如何。
文森特·吉盖尔
Since Groovy is dynamic, you could just take away your currentDate() method from your service and replace it by one that suits your need. You can do this at runtime during the setup of your test.
Prior to having an instance of MyService instantiated, have the following code executed:
This way, you can have a consistent behavior across all your tests.
However, if you prefer, you can override the instance method by a closure that does the same trick.
Let me know how it goes.
Vincent Giguère