Java 是否有一种更简洁的方法来测试对列表中每个项的模拟方法的调用
这是我最近经常遇到的一个模式的例子。 我有一个要测试的方法,它接受一个列表,并且可以为列表中的每个项目调用一些其他方法。为了测试这一点,我定义了一个具有预期调用参数的迭代器,并在JMock预期中定义了一个循环,以检查是否针对迭代器的每个项进行了调用(请参见下面的简单示例) 我已经看过Hamcrest matchers,但还没有找到对此进行测试的东西(或者误解了可用matchers的工作原理)。有人有更优雅的方法吗Java 是否有一种更简洁的方法来测试对列表中每个项的模拟方法的调用,java,unit-testing,jmock,jmockit,Java,Unit Testing,Jmock,Jmockit,这是我最近经常遇到的一个模式的例子。 我有一个要测试的方法,它接受一个列表,并且可以为列表中的每个项目调用一些其他方法。为了测试这一点,我定义了一个具有预期调用参数的迭代器,并在JMock预期中定义了一个循环,以检查是否针对迭代器的每个项进行了调用(请参见下面的简单示例) 我已经看过Hamcrest matchers,但还没有找到对此进行测试的东西(或者误解了可用matchers的工作原理)。有人有更优雅的方法吗 package com.hsbc.maven.versionupdater; i
package com.hsbc.maven.versionupdater;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.maven.plugin.testing.AbstractMojoTestCase;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.Sequence;
import org.jmock.internal.NamedSequence;
public class FooTest extends AbstractMojoTestCase {
public interface Bar {
void doIt(String arg);
}
public class Foo {
private Bar bar;
public void executeEven(final List<String> allParameters) {
for (int i = 0; i < allParameters.size(); i++) {
if (i % 2 == 0) {
bar.doIt(allParameters.get(i));
}
}
}
public Bar getBar() {
return bar;
}
public void setBar(final Bar bar) {
this.bar = bar;
}
}
public void testExecuteEven() {
Mockery mockery = new Mockery();
final Bar bar = mockery.mock(Bar.class);
final Sequence sequence = new NamedSequence("sequence");
final List<String> allParameters = new ArrayList<String>();
final List<String> expectedParameters = new ArrayList<String>();
for (int i = 0; i < 3; i++) {
allParameters.add("param" + i);
if (i % 2 == 0) {
expectedParameters.add("param" + i);
}
}
final Iterator<String> iter = expectedParameters.iterator();
mockery.checking(new Expectations() {
{
while (iter.hasNext()) {
one(bar).doIt(iter.next());
inSequence(sequence);
}
}
});
Foo subject = new Foo();
subject.setBar(bar);
subject.executeEven(allParameters);
mockery.assertIsSatisfied();
}
}
package com.hsbc.maven.versionUpdate;
导入java.util.ArrayList;
导入java.util.Iterator;
导入java.util.List;
导入org.apache.maven.plugin.testing.AbstractMojoTestCase;
导入org.jmock.expections;
导入org.jmock.mockry;
导入org.jmock.Sequence;
导入org.jmock.internal.NamedSequence;
公共类FooTest扩展了AbstractMojoTestCase{
公共接口栏{
void doIt(字符串arg);
}
公开课Foo{
私人酒吧;
public void executeEven(最终列出所有参数){
对于(int i=0;i
可能是以下情况(使用JMockit而不是jMock)
导入java.util.*;
导入org.junit.*;
导入org.junit.runner.*;
导入org.hamcrest.*;
导入静态org.hamcrest.core.AnyOf.*;
导入静态org.hamcrest.core.Is.*;
导入org.hamcrest.core.*;
输入mockit.*;
导入mockit.integration.junit4.*;
@RunWith(JMockit.class)
公务舱
{
公共接口栏{void doIt(字符串arg);}
公开课Foo
{
私人酒吧;
public void executeEven(最终列出所有参数)
{
对于(int i=0;i 最终列表我认为您当前的测试实现非常接近理想状态。任何进一步的压缩都有可能改变测试的语义,或对读者模糊测试的意图(或两者兼而有之)
但是,如果您正在寻找一种方法来期望对某个方法进行特定数量的调用,则可以使用精确地(n).of()
:
(我省略了均匀度检查,但你明白了)。这与jmockit示例中的不同答案类似。请注意,这不会测试与原始测试相同的内容。特别是,它不会检查:
调用doIt
参数列表的每个元素只传递一次
例如,如果您的方法以相反的顺序迭代列表,或者如果它只调用了doIt
方法n
次,但每次都通过列表的第一个元素,则此测试将通过。如果您希望确保列表中的每个元素都通过,则您几乎必须对其进行迭代,设置一个单独的expecta如果您不关心调用的顺序,可以省略序列的使用(在这种情况下,您可能希望更改原始方法以接受集合而不是列表)。您可以简化此测试。您知道自己想要什么,因此可以更具体地描述代码:
public void testExecuteEven() {
final List<String> values = Arrays.asList("param0", "param1", "param2", "param3");
Sequence evens = mockery.sequence("evens");
mockery.checking(new Expectations() {{
oneOf(bar).doIt(values.get(0)); inSequence(evens);
oneOf(bar).doIt(values.get(2)); inSequence(evens);
}});
subject.executeEven(values);
}
public void testExecuteEven(){
最终列表值=Arrays.asList(“param0”、“param1”、“param2”、“param3”);
序列evens=嘲弄。序列(“evens”);
嘲弄。检查(新期望(){{
(bar.doIt(values.get(0));不连续(evens);
其中一个是bar.doIt(values.get(2));inSequence(evens);
}});
受试者。执行者(价值观);
}
如果您使用的是JUnit 4,请不要忘记,类上的@RunWith(JMock.class)注释避免了assertessatified()调用的需要。值得记住的是,您不必一次创建所有期望值。您可以在检查(new expectations(){}}之外执行循环
在最终将期望列表传递给模拟之前,阻止并操纵期望列表。这有助于在复杂的期望设置中保持清晰(评论也是如此!):
@测试
public void testExecuteEven(){
嘲弄嘲弄=新嘲弄();
序列evens=嘲弄。序列(“evens”);
最终Bar=mockry.mock(Bar.class);
列表期望值=新的ArrayList();
最终列表allParameters=new ArrayList();
最终列表expectedParameters=new ArrayList();
//生成一些参数
对于(int i=0;i<3;i++){
所有参数。添加(“参数”+i);
如果(i%2==0)
mockery.checking(new Expectations() {{
exactly(expectedParameters.length()).of(bar).doIt(with(anyOf(expectedParameters)));
}});
public void testExecuteEven() {
final List<String> values = Arrays.asList("param0", "param1", "param2", "param3");
Sequence evens = mockery.sequence("evens");
mockery.checking(new Expectations() {{
oneOf(bar).doIt(values.get(0)); inSequence(evens);
oneOf(bar).doIt(values.get(2)); inSequence(evens);
}});
subject.executeEven(values);
}
@Test
public void testExecuteEven() {
Mockery mockery = new Mockery();
Sequence evens = mockery.sequence("evens");
final Bar bar = mockery.mock(Bar.class);
List<Expectations> expectations = new ArrayList<Expectations>();
final List<String> allParameters = new ArrayList<String>();
final List<String> expectedParameters = new ArrayList<String>();
// generate some parameters
for (int i = 0; i < 3; i++) {
allParameters.add("param" + i);
if (i % 2 == 0) {
expectedParameters.add("param" + i);
}
}
// define expectations for the expected parameters
for (String param : expectedParameters) {
expectations.add(new Expectations() {{ oneOf(bar).doIt(param); inSequence(evens); }});
}
// define any special expectations here
expectations.add(new Expectations() {{ oneOf(bar).doSomethingElse() /* whatever */ }});
// load the expectations into the mockery
for (Expectations expectation : expectations) {
mockery.checking(expectation);
}
Foo subject = new Foo();
subject.setBar(bar);
subject.executeEven(allParameters);
}