我有一个测试,其中我有一组特定的值,对于集合中的每个值,两个不同的方法将执行一次。我需要检查两个方法是否以特定的顺序相互调用,而不是与值集的顺序相关。例如:
String[] values = { "A", "B", "C" };
for (...<loop over values...) {
methodOne(value);
methodTwo(value);
}
values
的顺序无关紧要,但我需要验证为集合中的每个值调用methodOne()
和methodTwo()
并且methodOne()
是总是在methodTwo()
之前调用。
我知道我可以为每个值创建一个控件并期望methodOne()
和methodTwo()
,然后执行control.verify()
,但这取决于values
按特定顺序排列
有优雅的方法吗?
由于
答案 0 :(得分:0)
您可以使用andAnswer()
。
基本上,在来自andAnswer()
的{{1}}内,您设置了一些变量来保存methodOne()
中传递的内容。
然后在value
andAnswer()
中你断言同一个参数与你从methodOne答案中保存的那个匹配。
由于每次调用methodTwo()
都会修改此变量,因此将确保始终在methodOne()之后调用methodTwo()。
注意此解决方案不是线程安全的
首先,你需要一些东西来保存methodOne调用中的变量。这可以是具有单个字段的简单类,甚至是一个元素的数组。您需要此包装器对象,因为您需要在IAnswer中引用它,这需要最终或有效的最终字段。
methodOne
现在你的期望。在这里,我调用了您正在测试的类(被测系统)private class CurrentValue{
private String methodOneArg;
}
:
sut
修改强>
你是对的,如果你使用的是EasyMock 2.4 +,你可以使用新的 String[] values = new String[]{"A", "B", "C"};
final CurrentValue currentValue = new CurrentValue();
sut.methodOne(isA(String.class));
expectLastCall().andAnswer(new IAnswer<Void>() {
@Override
public Void answer() throws Throwable {
//save the parameter passed in to our holder object
currentValue.methodOneArg =(String) EasyMock.getCurrentArguments()[0];
return null;
}
}).times(values.length); // do this once for every element in values
sut.methodTwo(isA(String.class));
expectLastCall().andAnswer(new IAnswer<Void>() {
@Override
public Void answer() throws Throwable {
String value =(String) EasyMock.getCurrentArguments()[0];
//check to make sure the parameter matches the
//the most recent call to methodOne()
assertEquals(currentValue.methodOneArg, value);
return null;
}
}).times(values.length); // do this once for every element in values
replay(sut);
... //do your test
verify(sut);
类以更清晰的方式获取Capture
的参数值。但是,您可能仍需要使用methodOne()
andAnswer()
来确保按顺序调用正确的值。
以下是使用Capture
的相同代码methodTwo()
答案 1 :(得分:0)
对于那些感兴趣的人,我使用预期的EasyMock功能解决了这个问题。解决方案是创建一个自定义IArgumentMatcher来验证一组值,并强制每个值连续匹配多少次。自定义匹配器,除了使用严格的模拟外,还能完全解决原始问题。
public class SetMatcher implements IArgumentMatcher {
private List<String> valuesToMatch;
private List<String> remainingValues;
private String currentValue = null;
private int timesMatched = 0;
private int setMatches;
public SetMatcher(final List<String> valuesToMatch, final int times) {
this.valuesToMatch = new ArrayList<String>(valuesToMatch);
this.remainingValues = new ArrayList<String>(valuesToMatch);
this.setMatches = times;
}
public String use() {
EasyMock.reportMatcher(this);
return null;
}
public void appendTo(StringBuffer buffer) {
if (this.remainingValues.size() == 0) {
buffer.append("all values in " + this.valuesToMatch + " already matched " + this.setMatches + " time(s)");
} else {
buffer.append("match " + this.valuesToMatch + " " + this.setMatches + " time(s) each");
}
}
public boolean matches(Object other) {
if (this.timesMatched >= this.setMatches) {
this.currentValue = null;
this.timesMatched = 0;
}
if (null == this.currentValue) {
if (this.remainingValues.contains(other)) {
this.currentValue = (String) other;
this.timesMatched = 1;
this.remainingValues.remove(other);
return true;
}
} else if (this.currentValue.equals(other)) {
this.timesMatched++;
return true;
}
return false;
}
}
正在测试的课程:
public class DataProcessor {
private ServiceOne serviceOne;
private ServiceTwo serviceTwo;
public DataProcessor(ServiceOne serviceOne, ServiceTwo serviceTwo) {
this.serviceOne = serviceOne;
this.serviceTwo = serviceTwo;
}
public void processAll(List<String> allValues) {
List<String> copy = new ArrayList<String>(allValues);
for (String value : copy) {
this.serviceOne.preProcessData(value);
this.serviceTwo.completeTransaction(value);
}
}
}
测试:
public class DataProcessorTest {
List<String> TEST_VALUES = Arrays.asList("One", "Two", "Three", "Four", "Five");
@Test
public void test() {
IMocksControl control = EasyMock.createStrictControl();
ServiceOne serviceOne = control.createMock(ServiceOne.class);
ServiceTwo serviceTwo = control.createMock(ServiceTwo.class);
SetMatcher matcher = new SetMatcher(TEST_VALUES, 2);
for (int i = 0; i < TEST_VALUES.size(); i++) {
serviceOne.preProcessData(matcher.use());
serviceTwo.completeTransaction(matcher.use());
}
control.replay();
DataProcessor dataProcessor = new DataProcessor(serviceOne, serviceTwo);
dataProcessor.processAll(TEST_VALUES);
control.verify();
}
}
以下任何一项测试都将失败: