有没有更好的方法来添加多个模拟交互?
Is there a better way to add multiple mocked interactions?
我正在寻找一种更好的方法来在 class.
中添加同一方法的多个交互
给定一个对象列表,我想根据这些对象执行过滤器,并且我想为每个剩余对象添加 Spock 交互
我最好的工作实现(使用 Java8 流和 for 循环来添加交互):
SomeClassA classA = Mock() {
def listOfDesiredObjects = listOfObjects
.stream()
.filter({i -> i != someObject})
.map({i -> new DesiredObject(i)})
.collect(Collectors.toList())
for (int i = 0; i < listOfDesiredObjects.size(); i++) {
methodIWantToMockMultipleTimes(_ as Type0, listOfDesiredObjects.get(i) as Type1) >> {
return someMockedObject
}
}
methodIWantToMockMultipleTimes(_ as Type0, someObject as Type1) >> {
return someDifferentMockedObject
}
}
我尝试了以下方法,但它们要么无法编译,要么就是乱七八糟(在我看来):
以下将return一个Groovyc: Interaction is missing a target
错误:
SomeClassA classA = Mock() {
def listOfDesiredObjects = listOfObjects
.stream()
.filter({i -> i != someObject})
.map({i -> new DesiredObject(i)})
.forEach({i -> methodIWantToMockMultipleTimes(_ as Type0, listOfDesiredObjects.get(i) as Type1) >> {
return someMockedObject
}})
methodIWantToMockMultipleTimes(_ as Type0, someObject as Type1) >> {
return someDifferentMockedObject
}
}
这很糟糕:
SomeClassA classA = Mock() {
methodIWantToMockMultipleTimes(_ as Type0, listOfDesiredObjects.get(0) as Type1) >> {
return someMockedObject
}
methodIWantToMockMultipleTimes(_ as Type0, listOfDesiredObjects.get(1) as Type1) >> {
return someMockedObject
}
// {n} more interactions
methodIWantToMockMultipleTimes(_ as Type0, someObject as Type1) >> {
return someDifferentMockedObject
}
}
供将来参考(我最终如何利用参数匹配器):
def classToMock = Mock() {
methodToMock(_ as Type0, _ as Type1, _ as Type2) >> { Type0 a, Type1 objectToCompare, Type2 c ->
listOfObjects
.stream()
.map({i -> someHelperMethod(i)})
.filter({i -> i == objectToCompare})
.map({i -> desiredObject })
.findFirst()
.orElse({i -> otherObject})
}
}
用户chrylis说得对,如果使用参数匹配,解决方案其实很简单。我根据您的(伪)代码(包括虚拟 类)重新创建了您的情况,以便向您展示简化方法的不同方法:
以下是备选方案的关键部分:
def "simplified test with two distinct cases"() {
given:
def someObject = new DesiredObject("C")
SomeClassA classA = Mock() {
methodIWantToMockMultipleTimes(_, !someObject) >> someMockedObject
methodIWantToMockMultipleTimes(_, someObject) >> someDifferentMockedObject
}
// (...)
}
def "simplified test with special and default case"() {
given:
def someObject = new DesiredObject("C")
SomeClassA classA = Mock() {
// Attention, this only works if the special case is defined before the default one
methodIWantToMockMultipleTimes(_, someObject) >> someDifferentMockedObject
methodIWantToMockMultipleTimes(*_) >> someMockedObject
}
// (...)
}
def "simplified test with dynamic stub method"() {
given:
def someObject = new DesiredObject("C")
SomeClassA classA = Mock() {
methodIWantToMockMultipleTimes(*_) >> { a, b -> b == someObject ? someDifferentMockedObject : someMockedObject }
}
// (...)
}
这里是完整代码(只需复制、粘贴和 运行):
package de.scrum_master.Whosebug.q57210075
import spock.lang.Specification
import java.util.stream.Collectors
class ConditionalMockCreationTest extends Specification {
class Type0 {}
class DesiredObject {
String name
DesiredObject(String name) {
this.name = name
}
@Override
String toString() {
"DesiredObject('$name')"
}
boolean equals(o) {
if (this.is(o)) return true
if (getClass() != o.class) return false
DesiredObject that = (DesiredObject) o
if (name != that.name) return false
return true
}
int hashCode() {
return (name != null ? name.hashCode() : 0)
}
}
class SomeClassA {
DesiredObject methodIWantToMockMultipleTimes(Type0 type0, DesiredObject desiredObject) {
return new DesiredObject("default")
}
}
def someMockedObject = Mock(DesiredObject) {
toString() >> "some mocked object"
}
def someDifferentMockedObject = Mock(DesiredObject) {
toString() >> "some different mocked object"
}
def "original test"() {
given:
def listOfObjects = ["A", "B", "C", "D", "E"]
def someObject = "C"
SomeClassA classA = Mock() {
def listOfDesiredObjects = listOfObjects
.stream()
.filter({ i -> i != someObject })
.map({ i -> new DesiredObject(i) })
.collect(Collectors.toList())
for (int i = 0; i < listOfDesiredObjects.size(); i++) {
methodIWantToMockMultipleTimes(_ as Type0, listOfDesiredObjects.get(i) as DesiredObject) >> {
return someMockedObject
}
}
methodIWantToMockMultipleTimes(_ as Type0, new DesiredObject(someObject)) >> {
return someDifferentMockedObject
}
}
expect: "normal object yields normal result"
new SomeClassA().methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("A")).toString() == "DesiredObject('default')"
and: "mocked objects yield predefined mock behaviour"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("A")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("B")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("C")).toString() == "some different mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("D")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("E")).toString() == "some mocked object"
// Undefined case -> no stubbed method -> mock returns null
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("XXX")) == null
}
def "simplified test with two distinct cases"() {
given:
def someObject = new DesiredObject("C")
SomeClassA classA = Mock() {
methodIWantToMockMultipleTimes(_, !someObject) >> someMockedObject
methodIWantToMockMultipleTimes(_, someObject) >> someDifferentMockedObject
}
expect: "normal object yields normal result"
new SomeClassA().methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("A")).toString() == "DesiredObject('default')"
and: "mocked objects yield predefined mock behaviour"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("A")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("B")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("C")).toString() == "some different mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("D")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("E")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("XXX")).toString() == "some mocked object"
}
def "simplified test with special and default case"() {
given:
def someObject = new DesiredObject("C")
SomeClassA classA = Mock() {
// Attention, this only works if the special case is defined before the default one
methodIWantToMockMultipleTimes(_, someObject) >> someDifferentMockedObject
methodIWantToMockMultipleTimes(*_) >> someMockedObject
}
expect: "normal object yields normal result"
new SomeClassA().methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("A")).toString() == "DesiredObject('default')"
and: "mocked objects yield predefined mock behaviour"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("A")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("B")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("C")).toString() == "some different mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("D")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("E")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("XXX")).toString() == "some mocked object"
}
def "simplified test with dynamic stub method"() {
given:
def someObject = new DesiredObject("C")
SomeClassA classA = Mock() {
methodIWantToMockMultipleTimes(*_) >> { a, b -> b == someObject ? someDifferentMockedObject : someMockedObject }
}
expect: "normal object yields normal result"
new SomeClassA().methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("A")).toString() == "DesiredObject('default')"
and: "mocked objects yield predefined mock behaviour"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("A")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("B")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("C")).toString() == "some different mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("D")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("E")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("XXX")).toString() == "some mocked object"
}
}
我正在寻找一种更好的方法来在 class.
中添加同一方法的多个交互给定一个对象列表,我想根据这些对象执行过滤器,并且我想为每个剩余对象添加 Spock 交互
我最好的工作实现(使用 Java8 流和 for 循环来添加交互):
SomeClassA classA = Mock() {
def listOfDesiredObjects = listOfObjects
.stream()
.filter({i -> i != someObject})
.map({i -> new DesiredObject(i)})
.collect(Collectors.toList())
for (int i = 0; i < listOfDesiredObjects.size(); i++) {
methodIWantToMockMultipleTimes(_ as Type0, listOfDesiredObjects.get(i) as Type1) >> {
return someMockedObject
}
}
methodIWantToMockMultipleTimes(_ as Type0, someObject as Type1) >> {
return someDifferentMockedObject
}
}
我尝试了以下方法,但它们要么无法编译,要么就是乱七八糟(在我看来):
以下将return一个Groovyc: Interaction is missing a target
错误:
SomeClassA classA = Mock() {
def listOfDesiredObjects = listOfObjects
.stream()
.filter({i -> i != someObject})
.map({i -> new DesiredObject(i)})
.forEach({i -> methodIWantToMockMultipleTimes(_ as Type0, listOfDesiredObjects.get(i) as Type1) >> {
return someMockedObject
}})
methodIWantToMockMultipleTimes(_ as Type0, someObject as Type1) >> {
return someDifferentMockedObject
}
}
这很糟糕:
SomeClassA classA = Mock() {
methodIWantToMockMultipleTimes(_ as Type0, listOfDesiredObjects.get(0) as Type1) >> {
return someMockedObject
}
methodIWantToMockMultipleTimes(_ as Type0, listOfDesiredObjects.get(1) as Type1) >> {
return someMockedObject
}
// {n} more interactions
methodIWantToMockMultipleTimes(_ as Type0, someObject as Type1) >> {
return someDifferentMockedObject
}
}
供将来参考(我最终如何利用参数匹配器):
def classToMock = Mock() {
methodToMock(_ as Type0, _ as Type1, _ as Type2) >> { Type0 a, Type1 objectToCompare, Type2 c ->
listOfObjects
.stream()
.map({i -> someHelperMethod(i)})
.filter({i -> i == objectToCompare})
.map({i -> desiredObject })
.findFirst()
.orElse({i -> otherObject})
}
}
用户chrylis说得对,如果使用参数匹配,解决方案其实很简单。我根据您的(伪)代码(包括虚拟 类)重新创建了您的情况,以便向您展示简化方法的不同方法:
以下是备选方案的关键部分:
def "simplified test with two distinct cases"() {
given:
def someObject = new DesiredObject("C")
SomeClassA classA = Mock() {
methodIWantToMockMultipleTimes(_, !someObject) >> someMockedObject
methodIWantToMockMultipleTimes(_, someObject) >> someDifferentMockedObject
}
// (...)
}
def "simplified test with special and default case"() {
given:
def someObject = new DesiredObject("C")
SomeClassA classA = Mock() {
// Attention, this only works if the special case is defined before the default one
methodIWantToMockMultipleTimes(_, someObject) >> someDifferentMockedObject
methodIWantToMockMultipleTimes(*_) >> someMockedObject
}
// (...)
}
def "simplified test with dynamic stub method"() {
given:
def someObject = new DesiredObject("C")
SomeClassA classA = Mock() {
methodIWantToMockMultipleTimes(*_) >> { a, b -> b == someObject ? someDifferentMockedObject : someMockedObject }
}
// (...)
}
这里是完整代码(只需复制、粘贴和 运行):
package de.scrum_master.Whosebug.q57210075
import spock.lang.Specification
import java.util.stream.Collectors
class ConditionalMockCreationTest extends Specification {
class Type0 {}
class DesiredObject {
String name
DesiredObject(String name) {
this.name = name
}
@Override
String toString() {
"DesiredObject('$name')"
}
boolean equals(o) {
if (this.is(o)) return true
if (getClass() != o.class) return false
DesiredObject that = (DesiredObject) o
if (name != that.name) return false
return true
}
int hashCode() {
return (name != null ? name.hashCode() : 0)
}
}
class SomeClassA {
DesiredObject methodIWantToMockMultipleTimes(Type0 type0, DesiredObject desiredObject) {
return new DesiredObject("default")
}
}
def someMockedObject = Mock(DesiredObject) {
toString() >> "some mocked object"
}
def someDifferentMockedObject = Mock(DesiredObject) {
toString() >> "some different mocked object"
}
def "original test"() {
given:
def listOfObjects = ["A", "B", "C", "D", "E"]
def someObject = "C"
SomeClassA classA = Mock() {
def listOfDesiredObjects = listOfObjects
.stream()
.filter({ i -> i != someObject })
.map({ i -> new DesiredObject(i) })
.collect(Collectors.toList())
for (int i = 0; i < listOfDesiredObjects.size(); i++) {
methodIWantToMockMultipleTimes(_ as Type0, listOfDesiredObjects.get(i) as DesiredObject) >> {
return someMockedObject
}
}
methodIWantToMockMultipleTimes(_ as Type0, new DesiredObject(someObject)) >> {
return someDifferentMockedObject
}
}
expect: "normal object yields normal result"
new SomeClassA().methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("A")).toString() == "DesiredObject('default')"
and: "mocked objects yield predefined mock behaviour"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("A")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("B")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("C")).toString() == "some different mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("D")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("E")).toString() == "some mocked object"
// Undefined case -> no stubbed method -> mock returns null
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("XXX")) == null
}
def "simplified test with two distinct cases"() {
given:
def someObject = new DesiredObject("C")
SomeClassA classA = Mock() {
methodIWantToMockMultipleTimes(_, !someObject) >> someMockedObject
methodIWantToMockMultipleTimes(_, someObject) >> someDifferentMockedObject
}
expect: "normal object yields normal result"
new SomeClassA().methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("A")).toString() == "DesiredObject('default')"
and: "mocked objects yield predefined mock behaviour"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("A")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("B")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("C")).toString() == "some different mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("D")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("E")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("XXX")).toString() == "some mocked object"
}
def "simplified test with special and default case"() {
given:
def someObject = new DesiredObject("C")
SomeClassA classA = Mock() {
// Attention, this only works if the special case is defined before the default one
methodIWantToMockMultipleTimes(_, someObject) >> someDifferentMockedObject
methodIWantToMockMultipleTimes(*_) >> someMockedObject
}
expect: "normal object yields normal result"
new SomeClassA().methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("A")).toString() == "DesiredObject('default')"
and: "mocked objects yield predefined mock behaviour"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("A")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("B")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("C")).toString() == "some different mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("D")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("E")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("XXX")).toString() == "some mocked object"
}
def "simplified test with dynamic stub method"() {
given:
def someObject = new DesiredObject("C")
SomeClassA classA = Mock() {
methodIWantToMockMultipleTimes(*_) >> { a, b -> b == someObject ? someDifferentMockedObject : someMockedObject }
}
expect: "normal object yields normal result"
new SomeClassA().methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("A")).toString() == "DesiredObject('default')"
and: "mocked objects yield predefined mock behaviour"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("A")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("B")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("C")).toString() == "some different mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("D")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("E")).toString() == "some mocked object"
classA.methodIWantToMockMultipleTimes(new Type0(), new DesiredObject("XXX")).toString() == "some mocked object"
}
}