覆盖 dateCreated 以在 Grails 中进行测试
有没有什么方法可以在不关闭自动时间戳的情况下覆盖域类中 dateCreated
字段的值?
我需要测试控制器,并且必须提供具有特定创建日期的特定域对象,但 GORM 似乎会覆盖我提供的值。
编辑
我的课程如下所示:
class Message {
String content
String title
User author
Date dateCreated
Date lastUpdated
static hasMany = [comments : Comment]
static constraints = {
content blank: false
author nullable: false
title nullable: false, blank: false
}
static mapping = {
tablePerHierarchy false
tablePerSubclass true
content type: "text"
sort dateCreated: 'desc'
}
}
class BlogMessage extends Message{
static belongsTo = [blog : Blog]
static constraints = {
blog nullable: false
}
}
我正在使用控制台来缩短时间。我在 Victor 的方法中遇到的问题是,当我写:
Date someValidDate = new Date() - (20*365)
BlogMessage.metaClass.setDateCreated = {
Date d ->
delegate.@dateCreated = someValidDate
}
我得到以下异常:
groovy.lang.MissingFieldException: No such field: dateCreated for class: pl.net.yuri.league.blog.BlogMessage
当我尝试
Message.metaClass.setDateCreated = {
Date d ->
delegate.@dateCreated = someValidDate
}
脚本运行良好,但不幸的是 dateCreated
没有被改变。
Is there any way I can override the value of dateCreated
field in my domain class without turning off auto timestamping?
I need to test controller and I have to provide specific domain objects with specific creation date but GORM seems to override values I provide.
Edit
My classes look like this:
class Message {
String content
String title
User author
Date dateCreated
Date lastUpdated
static hasMany = [comments : Comment]
static constraints = {
content blank: false
author nullable: false
title nullable: false, blank: false
}
static mapping = {
tablePerHierarchy false
tablePerSubclass true
content type: "text"
sort dateCreated: 'desc'
}
}
class BlogMessage extends Message{
static belongsTo = [blog : Blog]
static constraints = {
blog nullable: false
}
}
I'm using console to shorten things up. The problem which I encountered with Victor's approach is, when I write:
Date someValidDate = new Date() - (20*365)
BlogMessage.metaClass.setDateCreated = {
Date d ->
delegate.@dateCreated = someValidDate
}
I get following exception:
groovy.lang.MissingFieldException: No such field: dateCreated for class: pl.net.yuri.league.blog.BlogMessage
When I tried
Message.metaClass.setDateCreated = {
Date d ->
delegate.@dateCreated = someValidDate
}
Script goes well, but unfortunately dateCreated
is not being altered.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
我遇到了类似的问题,并且能够通过
作为参考,我的测试:
I was having a similar issue, and was able to overwrite dateCreated for my domain (in a Quartz Job test, so no @TestFor annotation on the Spec, Grails 2.1.0) by
For reference, my test:
掌握 ClosureEventListener 允许您暂时禁用 grails 时间戳。
可能有一种更简单的方法来获取 applicationContext 或 Hibernate 配置,但这在运行应用程序时对我有用。它在集成测试中不起作用,如果有人知道如何做到这一点,请告诉我。
更新
对于 Grails 2 使用 eventTriggeringInterceptor
Getting a hold of the ClosureEventListener allows you to temporarily disable grails timestamping.
There may be an easier way to get the applicationContext or Hibernate configuration but that worked for me when running the app. It does not work in an integration test, if anyone figures out how to do that let me know.
Update
For Grails 2 use eventTriggeringInterceptor
我通过简单地设置字段就得到了这个工作。诀窍是在首先保存域对象之后执行此操作。我假设 dateCreated 时间戳是在保存时设置的,而不是在对象创建时设置的。
沿着这些思路
使用 Grails 2.3.6
I got this working by simply setting the field. The trick was to do that after the domain object has been saved first. I assume that the dateCreated timestamp is set on save and not on object creation.
Something along these lines
Using Grails 2.3.6
从 Grails 3 和 GORM 6 开始,您可以利用
AutoTimestampEventListener
来执行暂时忽略所有或选择时间戳的Runnable
。以下是我在集成测试中使用的一个小片段,这是必要的:
那么在您的情况下,您可以执行以下操作:
As of Grails 3 and GORM 6 you can tap into
AutoTimestampEventListener
to execute aRunnable
that temporarily ignores all or select timestamps.The following is a small snippet I use in my integration tests where this is necessary:
Then in your case you could do the following:
我正在使用类似的东西进行初始导入/迁移。
以 gabe 的帖子作为入门(这对我的 Grails 2.0 不起作用),并查看 Grails 1.3.7 中 ClosureEventTriggeringInterceptor 的旧源代码,我想出了这个:
I'm using something like this for an initial import/migration.
Taking gabe's post as a starter (which didn't work for me Grails 2.0), and looking at the old source code for ClosureEventTriggeringInterceptor in Grails 1.3.7, I came up with this:
您可以尝试通过在域类映射中设置
autoTimestamp = false
来禁用它。我对全局覆盖表示怀疑,因为该值是直接从 System.currentTimeMillis() 获取的(我正在查看 org.codehaus.groovy.grails.orm。 hibernate.support.ClosureEventListener.java)。因此,我只能建议您重写类中
dateCreated
字段的设置器,并分配您自己的值。也许甚至元类访问也可以工作,比如You can try to disable it by setting
autoTimestamp = false
in the domain class mapping. I doubt about global overriding because the value is taken directly fromSystem.currentTimeMillis()
(I'm looking at org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventListener.java).So I can only suggest that you override a setter for
dateCreated
field in your class, and assign your own value. Maybe even metaclass access will work, like我无法使上述技术发挥作用,对 GrailsDomainBinder.getMapping 的调用始终返回 null???
但是...
您可以使用固定插件在域实例上设置 dateCreated 属性
初始加载不会执行此操作...
但是如果您使用后处理程序
此处的装置文档的相关部分
AFAIK装置不适用于单元测试,尽管插件作者将来可能会添加单元测试支持。
I couldn't get the above techniques to work, the call to GrailsDomainBinder.getMapping always returned null???
However...
You can use the fixtures plugin to set the dateCreated property on a domain instance
The initial loading will not do it...
but if you follow up with a post handler
Relevant part of the fixtures docs here
AFAIK fixtures don't work for unit testing, although the plugin authors may add unit testing support in the future.
一个更简单的解决方案是在集成测试中使用 SQL 查询,在使用所需的其他值初始化对象后根据需要进行设置。
A simpler solution is to use a SQL query in your integration test to set it as you please after you initialize your object with the other values you want.
从 grails 2.5.1 开始,GrailsDomainBinder 类的 getMapping() 方法不是静态的,上述方法都不能按原样工作。然而,@Volt0 的方法只需稍加调整即可工作。由于我们所有人都试图这样做以使我们的测试正常工作,所以我没有将其放置在 BootStrap 中,而是将其放置在实际的集成测试中。这是我对 Volt0 方法的调整:
并且只需在测试中调用这些方法,例如
上面的代码也可以放置在 src 目录中,并且可以在测试中调用,但是我将其放置在实际测试中,因为我的应用程序中只有一个类需要这个。
As of grails 2.5.1, getMapping() method of GrailsDomainBinder class is not static,non of the above method works as is. However, @Volt0's method works with minor tweaking. Since all of us are trying to do so to make our tests working, instead of placing it in BootStrap, I placed it in actual integration test. Here is my tweak to Volt0's method:
And simply call these methods in tests like
The above code can also be placed in src directory and can be called in tests however I placed this in actual test as there was only one class in my app where I needed this.
简单的解决方案是添加映射:
The easy solution is to add a mapping: