mik*_*ent 2 testing groovy singleton spock
有商榷这里有关测试和单身......但是这是关于Java模式。
我的问题特别是关于@Singleton实现此模式的Groovy (注释)方式的。
这似乎是Groovy Goodness的另一点。但是,在使用具有此批注的类进行测试(使用Spock)时,我有一个问题。
如果测试(从原始的,只是构建的状态)在任何的这个实例的状态发生变化的,据我的实验表明,那么这将通过进行下一个测试...我测试MySingletonClass.instance的hashCode()几个测试和他们都回来了一样。也许这并不奇怪。
但是...如果Spock能够(使用我只能推测的那种超级格罗维魔术)以某种方式重置测试之间的类,那会更好吗?即通过创建新实例?
有一个明显的解决方法:将一个reset方法合并到每个@Singleton类中,在测试期间其状态可能会更改。然后reset在setup()...中调用该方法,实际上我使用了一个公共Specification子类CommonProjectSpec,从中可以得到我所有的Specifications子类...这样就很容易实现。
但这似乎有点不雅。还有其他选择吗?我应该将其作为Spock建议的增强功能提交吗?
PS还可以证明您不能再创建Spy此类(或GroovySpy)。但是您可以使用Mock它:
ConsoleHandler mockCH = Mock( ConsoleHandler ){
getDriver() >> ltfm
}
GroovyMock( ConsoleHandler, global: true )
ConsoleHandler.instance = mockCH
Run Code Online (Sandbox Code Playgroud)
...是的,GroovyMock这里的“全局” 实际上具有“驯服”静态instance场的能力,以便它温柔地接受Mock巢中的杜鹃。
所以基本上您想测试一个单例不是一个单例。这让我感到很奇怪。但是无论如何,我将这个问题视为一个难题,我将自己解决这个难题,因为这是一个很好的挑战。(孩子们,不要在家做!)
Groovy单例:
package de.scrum_master.stackoverflow
@Singleton
class Highlander {
def count = 0
def fight() {
println "There can be only one!"
count++
doSomething()
}
def doSomething() {
println "Doing something"
}
}
Run Code Online (Sandbox Code Playgroud)
单例助手类:
package de.scrum_master.stackoverflow
import java.lang.reflect.Field
import java.lang.reflect.Modifier
class GroovySingletonTool<T> {
private Class<T> clazz
GroovySingletonTool(Class<T> clazz) {
this.clazz = clazz
}
void setSingleton(T instance) {
// Make 'instance' field non-final
Field field = clazz.getDeclaredField("instance")
field.modifiers &= ~Modifier.FINAL
// Only works if singleton instance was unset before
field.set(clazz.instance, instance)
}
void unsetSingleton() {
setSingleton(null)
}
void reinitialiseSingleton() {
// Unset singleton instance, otherwise subsequent constructor call will fail
unsetSingleton()
setSingleton(clazz.newInstance())
}
}
Run Code Online (Sandbox Code Playgroud)
Spock测试:
该测试显示了如何
Stub()Groovy单例Mock()Groovy单例Spy()Groovy单例(需要Objenesis)package de.scrum_master.stackoverflow
import org.junit.Rule
import org.junit.rules.TestName
import spock.lang.Specification
import spock.lang.Unroll
class HighlanderTest extends Specification {
def singletonTool = new GroovySingletonTool<Highlander>(Highlander)
@Rule
TestName gebReportingSpecTestName
def setup() {
println "\n--- $gebReportingSpecTestName.methodName ---"
}
@Unroll
def "Highlander fight no. #fightNo"() {
given:
singletonTool.reinitialiseSingleton()
def highlander = Highlander.instance
when:
highlander.fight()
then:
highlander.count == 1
where:
fightNo << [1, 2, 3]
}
@Unroll
def "Highlander stub fight no. #fightNo"() {
given:
Highlander highlanderStub = Stub() {
fight() >> { println "I am a stub" }
}
singletonTool.setSingleton(highlanderStub)
def highlander = Highlander.instance
when:
highlander.fight()
then:
highlander == highlanderStub
where:
fightNo << [1, 2, 3]
}
@Unroll
def "Highlander mock fight no. #fightNo"() {
given:
Highlander highlanderMock = Mock() {
fight() >> { println "I am just mocking you" }
}
singletonTool.setSingleton(highlanderMock)
def highlander = Highlander.instance
when:
highlander.fight()
then:
highlander == highlanderMock
0 * highlander.doSomething()
where:
fightNo << [1, 2, 3]
}
@Unroll
def "Highlander spy fight no. #fightNo"() {
given:
// Unset not necessary because Objenesis creates object without constructor call
// singletonTool.unsetSingleton()
Highlander highlanderSpy = Spy(useObjenesis: true)
// Spy's member is not initialised by Objenesis
highlanderSpy.count = 0
singletonTool.setSingleton(highlanderSpy)
def highlander = Highlander.instance
when:
highlander.fight()
then:
highlander == highlanderSpy
highlander.count == 1
1 * highlander.doSomething() >> { println "I spy" }
where:
fightNo << [1, 2, 3]
}
}
Run Code Online (Sandbox Code Playgroud)
控制台日志:
--- Highlander fight no. 1 ---
There can be only one!
Doing something
--- Highlander fight no. 2 ---
There can be only one!
Doing something
--- Highlander fight no. 3 ---
There can be only one!
Doing something
--- Highlander stub fight no. 1 ---
I am a stub
--- Highlander stub fight no. 2 ---
I am a stub
--- Highlander stub fight no. 3 ---
I am a stub
--- Highlander mock fight no. 1 ---
I am just mocking you
--- Highlander mock fight no. 2 ---
I am just mocking you
--- Highlander mock fight no. 3 ---
I am just mocking you
--- Highlander spy fight no. 1 ---
There can be only one!
I spy
--- Highlander spy fight no. 2 ---
There can be only one!
I spy
--- Highlander spy fight no. 3 ---
There can be only one!
I spy
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
636 次 |
| 最近记录: |