如何测试字段是否设置为特定值?
How can I test that a field is set to a certain value?
这看起来很基本,所以我希望这是一个骗局...但我还没有找到任何可以回答这个问题的东西。
我的应用代码也是Groovy。假设我有一个字段
def something
并且在我的测试中(CUT 是一个 Spock Spy
)我 运行 一个中间有一行的方法
something = null
或
something = new Bubble()
...我只是想找到一种方法来测试确实已将某些内容设置为 null
(或任何值...)
在我的 then
块中,我尝试过:
1 * spyCUT.setSomething( null )
和
1 * spyCUT.setSomething(_)
和
1 * spyCUT.set( 'something', _ )
顺便说一句,为了回答我可以在 then
块中测试 something
的值的反对意见,情况是 something
应该首先设置为一个值然后在这个方法的过程中到另一个...
读过 Groovy In Action 2nd Ed 我对 Groovy 如何处理获取和设置字段有最模糊的概念...显然不够。
MCVE(FWIW!)
class Spocko {
def something
def doStuff() {
something = 'fruit'
}
}
class SpockoTest extends Specification {
def 'test it'(){
given:
Spocko spySpocko = Spy( Spocko )
when:
spySpocko.doStuff()
then:
1 * spySpocko.setSomething(_)
}
}
稍后(在 kriegaex 非常有帮助的回复之后)
上面 SpockTest
其中 setSomething
是 调用:
class Spocko {
def something
def doStuff() {
this.each{
it.something = 'fruit'
}
}
}
...通过!我现在正在努力理解为什么...
顺便说一句,我还发现以下通过(并且没有关闭):
1 * spySpocko.setProperty( 'something', _ )
看了你的MCVE之后,问题可以这样回答:你不能测试一个从未发生过的方法调用。 doStuff()
只是给字段赋值,它不会在内部调用 setter 方法。看看这个:
package de.scrum_master.Whosebug
import spock.lang.Specification
class SpockoTest extends Specification {
static class Spocko {
def something
def doStuff() {
something = 'fruit'
}
def doMoreStuff() {
setSomething('vegetable')
}
}
def 'test it'(){
given: 'Spocko spy'
Spocko spySpocko = Spy(Spocko)
when: 'calling method assigning value to property'
spySpocko.doStuff()
then: 'no setter is called'
0 * spySpocko.setSomething(_)
spySpocko.something == 'fruit'
when: 'calling method using setter'
spySpocko.doMoreStuff()
then: 'setter gets called'
1 * spySpocko.setSomething('vegetable')
when: 'using Groovy setter-like syntax from another class'
spySpocko.something = 'fish'
then: 'actually a setter gets called'
1 * spySpocko.setSomething('fish')
}
}
事情是这样的。调用时
javap -v target/test-classes/de/scrum_master/Whosebug/SpockoTest$Spocko.class
你看(输出缩短):
public java.lang.Object doStuff();
descriptor: ()Ljava/lang/Object;
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=1
0: invokestatic #24 // Method $getCallSiteArray:()[Lorg/codehaus/groovy/runtime/callsite/CallSite;
3: astore_1
4: ldc #36 // String fruit
6: astore_2
7: aload_2
8: aload_0
9: swap
10: putfield #38 // Field something:Ljava/lang/Object;
13: aload_2
14: areturn
15: aconst_null
16: areturn
public java.lang.Object doMoreStuff();
descriptor: ()Ljava/lang/Object;
flags: ACC_PUBLIC
Code:
stack=3, locals=2, args_size=1
0: invokestatic #24 // Method $getCallSiteArray:()[Lorg/codehaus/groovy/runtime/callsite/CallSite;
3: astore_1
4: aload_1
5: ldc #40 // int 0
7: aaload
8: aload_0
9: ldc #42 // String vegetable
11: invokeinterface #48, 3 // InterfaceMethod org/codehaus/groovy/runtime/callsite/CallSite.callCurrent:(Lgroovy/lang/GroovyObject;Ljava/lang/Object;)Ljava/lang/Object;
16: areturn
17: aconst_null
18: areturn
你能看出区别吗?
问题编辑 2 后更新:您想知道为什么这会触发 setter 调用:
def doStuff() {
this.each {
it.something = 'fruit'
}
}
这是因为 this
作为参数提供给闭包,因此 it.something = 'fruit'
像我的示例一样动态解析 spySpocko.something = 'fish'
因为它不是内部赋值something = 'fruit'
(相当于this.something = 'fruit'
)了。
其实我觉得即使不看字节码也不难理解,只要按照通常的Groovy教程。我在重复我自己,但我确实认为你有点过度工程化和过度复杂化,测试太深了。我不会将这些测试放入生产代码库中。尝试测试您的 类 的行为(想想规格和功能!),而不是内部的复杂性。但如果它能帮助您了解 Groovy 的工作原理,请继续玩。
截至目前,请避免进一步的问题编辑和后续问题。如果你有新问题,最好用新的MCVE创建一个新问题。
这看起来很基本,所以我希望这是一个骗局...但我还没有找到任何可以回答这个问题的东西。
我的应用代码也是Groovy。假设我有一个字段
def something
并且在我的测试中(CUT 是一个 Spock Spy
)我 运行 一个中间有一行的方法
something = null
或
something = new Bubble()
...我只是想找到一种方法来测试确实已将某些内容设置为 null
(或任何值...)
在我的 then
块中,我尝试过:
1 * spyCUT.setSomething( null )
和
1 * spyCUT.setSomething(_)
和
1 * spyCUT.set( 'something', _ )
顺便说一句,为了回答我可以在 then
块中测试 something
的值的反对意见,情况是 something
应该首先设置为一个值然后在这个方法的过程中到另一个...
读过 Groovy In Action 2nd Ed 我对 Groovy 如何处理获取和设置字段有最模糊的概念...显然不够。
MCVE(FWIW!)
class Spocko {
def something
def doStuff() {
something = 'fruit'
}
}
class SpockoTest extends Specification {
def 'test it'(){
given:
Spocko spySpocko = Spy( Spocko )
when:
spySpocko.doStuff()
then:
1 * spySpocko.setSomething(_)
}
}
稍后(在 kriegaex 非常有帮助的回复之后)
上面 SpockTest
其中 setSomething
是 调用:
class Spocko {
def something
def doStuff() {
this.each{
it.something = 'fruit'
}
}
}
...通过!我现在正在努力理解为什么...
顺便说一句,我还发现以下通过(并且没有关闭):
1 * spySpocko.setProperty( 'something', _ )
看了你的MCVE之后,问题可以这样回答:你不能测试一个从未发生过的方法调用。 doStuff()
只是给字段赋值,它不会在内部调用 setter 方法。看看这个:
package de.scrum_master.Whosebug
import spock.lang.Specification
class SpockoTest extends Specification {
static class Spocko {
def something
def doStuff() {
something = 'fruit'
}
def doMoreStuff() {
setSomething('vegetable')
}
}
def 'test it'(){
given: 'Spocko spy'
Spocko spySpocko = Spy(Spocko)
when: 'calling method assigning value to property'
spySpocko.doStuff()
then: 'no setter is called'
0 * spySpocko.setSomething(_)
spySpocko.something == 'fruit'
when: 'calling method using setter'
spySpocko.doMoreStuff()
then: 'setter gets called'
1 * spySpocko.setSomething('vegetable')
when: 'using Groovy setter-like syntax from another class'
spySpocko.something = 'fish'
then: 'actually a setter gets called'
1 * spySpocko.setSomething('fish')
}
}
事情是这样的。调用时
javap -v target/test-classes/de/scrum_master/Whosebug/SpockoTest$Spocko.class
你看(输出缩短):
public java.lang.Object doStuff();
descriptor: ()Ljava/lang/Object;
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=1
0: invokestatic #24 // Method $getCallSiteArray:()[Lorg/codehaus/groovy/runtime/callsite/CallSite;
3: astore_1
4: ldc #36 // String fruit
6: astore_2
7: aload_2
8: aload_0
9: swap
10: putfield #38 // Field something:Ljava/lang/Object;
13: aload_2
14: areturn
15: aconst_null
16: areturn
public java.lang.Object doMoreStuff();
descriptor: ()Ljava/lang/Object;
flags: ACC_PUBLIC
Code:
stack=3, locals=2, args_size=1
0: invokestatic #24 // Method $getCallSiteArray:()[Lorg/codehaus/groovy/runtime/callsite/CallSite;
3: astore_1
4: aload_1
5: ldc #40 // int 0
7: aaload
8: aload_0
9: ldc #42 // String vegetable
11: invokeinterface #48, 3 // InterfaceMethod org/codehaus/groovy/runtime/callsite/CallSite.callCurrent:(Lgroovy/lang/GroovyObject;Ljava/lang/Object;)Ljava/lang/Object;
16: areturn
17: aconst_null
18: areturn
你能看出区别吗?
问题编辑 2 后更新:您想知道为什么这会触发 setter 调用:
def doStuff() {
this.each {
it.something = 'fruit'
}
}
这是因为 this
作为参数提供给闭包,因此 it.something = 'fruit'
像我的示例一样动态解析 spySpocko.something = 'fish'
因为它不是内部赋值something = 'fruit'
(相当于this.something = 'fruit'
)了。
其实我觉得即使不看字节码也不难理解,只要按照通常的Groovy教程。我在重复我自己,但我确实认为你有点过度工程化和过度复杂化,测试太深了。我不会将这些测试放入生产代码库中。尝试测试您的 类 的行为(想想规格和功能!),而不是内部的复杂性。但如果它能帮助您了解 Groovy 的工作原理,请继续玩。
截至目前,请避免进一步的问题编辑和后续问题。如果你有新问题,最好用新的MCVE创建一个新问题。