Groovy Singleton和测试问题(与Spock一起使用) [英] Groovy Singleton and testing issue (with Spock)

查看:141
本文介绍了Groovy Singleton和测试问题(与Spock一起使用)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此处上有关于测试和单例的讨论……但这是关于Java模式的讨论.

There's a discusson here about testing and singletons... but that is about Java patterns.

我的问题特别是关于Groovy @Singleton(注释)实现此模式的方式.

My question is specifically about the Groovy @Singleton (annotation) way of implementing this pattern.

这似乎又是Groovy Goodness的另一点.但是,在使用具有此批注的类进行测试(使用Spock)时,我有一个问题.

This seems like another bit of Groovy Goodness. But I have a bit of a problem when testing (with Spock) using a class which has this annotation.

如果该实例的任何状态在测试期间发生变化(从原始的刚刚构建的状态开始),只要我的实验表明这将继续进行下一个测试...我测试了MySingletonClass.instance' s hashCode()进行了几次测试,它们均返回相同的状态.也许这并不奇怪.

If any of the state of this instance changes during a test (from the pristine, just-constructed state), as far as my experiments indicate this will then carry through to the next test... I tested MySingletonClass.instance's hashCode() with several tests and they all came back the same. Perhaps this isn't surprising.

但是...如果Spock能够(使用我只能推测的那种超级格罗维魔术)以某种方式重置测试之间的类,那会不会更好呢? IE.通过创建一个新实例?

But ... wouldn't it be better if Spock could (using the kind of uber-Groovy magic I can only speculate on) somehow reset the class between tests? I.e. by creating a new instance?

有一个明显的解决方法:将reset方法合并到每个@Singleton类中,在测试过程中其状态可能会更改.然后在setup()中调用该reset方法...实际上,我使用了一个常见的Specification子类CommonProjectSpec,所有我的真正的Specification子类都来自该子类...这样就足够简单了实施.

There is an obvious workaround: to incorporate a reset method into each @Singleton class where its state might change during a test. And then call that reset method in setup() ... in fact I use a common Specification subclass, CommonProjectSpec, from which all my real Specifications subclass... so that would be simple enough to implement.

但是似乎有点不雅致.还有其他选择吗?我应该将其作为Spock建议的增强功能提交吗?

But it seems a bit inelegant. Is there any other option? Should I maybe submit this as a Spock suggested enhancement?

PS事实证明,您不能再创建此类的Spy(或GroovySpy).但是您可以将其制成Mock:

PS it also turns out you can't then make a Spy of this class (or a GroovySpy). But you can make a Mock of it:

    ConsoleHandler mockCH = Mock( ConsoleHandler ){
        getDriver() >> ltfm
    }
    GroovyMock( ConsoleHandler, global: true )
    ConsoleHandler.instance = mockCH

...是的,这里的全局" GroovyMock实际上具有驯服"静态instance字段的能力,这样它就可以轻松地在巢中接受Mock杜鹃.

... yes, the "global" GroovyMock here actually has the ability to "tame" the static instance field so that it meekly accepts a Mock cuckoo in the nest.

推荐答案

不幸的是,我遇到了Kriegax原本有用的解决方案的大问题.

Unfortunately I ran into big problems with Kriegax's otherwise helpful solution.

我做了很多实验,无法解释问题的根源.尽管有可能在此处提供了线索. (顺便说一句,在将新实例设置为单例实例之后,我确实尝试过立即应用修改器更改的想法,但这并不能解决问题.)

I've done quite a bit of experimentation and have been unable to explain where the problem comes from. Although there is a possible clue here. (Incidentally I did try this idea of applying the change of modifier immediately after setting the new instance to be the singleton instance... it did not solve the problem).

在典型情况下,我发现我可能有一个带有15个功能(测试)的Specification.单独运行它们可以正常工作:MySingleton.instance字段首先设置为null,然后设置为MySingleton的新实例.

In a typical situation I find I may have a Specification with maybe 15 features (tests). Running these on their own works fine: the MySingleton.instance field is set first to null and then to a new instance of MySingleton.

但是当我尝试使用另一个Specification的另一个xxx.groovy文件运行该程序时,它将对大约8个功能正常运行...但是我添加了一个新功能(即,我基本上对现有功能不加注释)正如我所见)突然出现了问题:MySingleton.instance可以设置为null ...,但是拒绝将点空白设置为新实例.我什至尝试了for循环和Thread.sleep()来查看多次尝试是否可以解决它.

But then when I try to run this with another xxx.groovy file with another Specification, it will work OK for about 8 features ... but then I add a new feature (i.e. I'm basically uncommenting existing features as I go) suddenly the problem crops up: MySingleton.instance can be set to null... but refuses point blank to be set to a new instance. I even tried a for loop with a Thread.sleep() to see if trying multiple times might solve it.

自然地,我然后看看刚刚添加的令人反感的功能:但是,没有什么是我在其他功能中没有做过的.更糟糕的是,接下来的事情是:我然后发现这些结果不一致:有时,有问题的"新功能(一旦取消注释)就不会在另一个.groovy文件中触发Field.set( ... )的失败.顺便说一下,在任何情况下Field.set( ... )都不会抛出Exception.

Naturally I then had a look at the offending feature which had just been added: but there was nothing there that I hadn't done in other features. Worse, far worse, follows: I then find that these results are not consistent: sometimes the "offending" new feature, once uncommented, does NOT then trigger the failure of Field.set( ... ) in the other .groovy file. By the way, no Exception is thrown by Field.set( ... ) during any of this.

应该指出的是,field.modifiers &= ~Modifier.FINAL据说是黑客",如此处,例如,有关其用法的许多警告.

It should be noted, en passant, that field.modifiers &= ~Modifier.FINAL is said to be "a hack", as described here, for example, with many caveats about its use.

因此,我很不情愿地得出以下结论:如果要使用Groovy拥有一个或多个单例类,则必须拥有一个reset方法,该方法可以保证将实例返回到原始状态(新构造) )状态,否则您必须放弃使用@Singleton注释(即,如果您热衷于为每个功能构建一个新实例).

I've therefore reluctantly come to the conclusion that if you want to have one or more singleton classes with Groovy you either have to have a reset method, which can be guaranteed to return the instance to a pristine (newly constructed) state, or you have to abandon use of the @Singleton annotation (i.e. if you are keen to construct a new instance with each feature).

这篇关于Groovy Singleton和测试问题(与Spock一起使用)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆