我有以下课程:
public class A {
private Field field;
public A(Field field){
this.field = field;
}
public add(int size){
field.addBall(new Ball(size));
}
}
public interface Things {
List<Ball> ballList = new LinkedList<>();
public addBall(Ball b){
ballList.add(b);
}
}
我想测试A类的add()方法。更具体地说,我想测试是否调用类Things的addBall()方法。 此测试失败说:验证时出现预期失败:Things.addBall(...):expected:1,actual:0;
public class TestA {
private Things thing;
private A a;
@Before
public void setUp() {
thing = EasyMock.createNiceMock(Things.class);
a = new A(thing);
}
@After
public void tearDown() {
}
@Test
public void addTest(){
thing.addBall(new Ball(345));
EasyMock.expectLastCall();
EasyMock.replay(cache);
a.add(345);
EasyMock.verify(cache);
}
}
什么是正确的方法?这个测试有什么问题?
答案 0 :(得分:1)
我通常和Mockito一起去,但这是我的猜测:
当EasyMock将您传递到录制阶段的new Ball(345)
的结果与new Ball(size)
内a.add(345)
的结果进行比较时,您会看到两个完全不同的Ball
对象。它们不会比较equal()
,尽管大小相同。
作为一般规则,当您进行测试时,对new
的显式调用会出现问题。一种可能的解决方案是引入BallFactory
。然后,您可以验证是否已调用factory.createBall(345)
,其结果是Ball
的模拟是传递给addBall()
(以下是关于此主题的优秀文章:http://misko.hevery.com/2008/07/08/how-to-think-about-the-new-operator/)
如果你宁愿放松你的测试要求,只是检查是否用任何对象调用addBall()
(我建议不要这样做),你可以使用EasyMock的anyObject()方法匹配任何Ball
。
答案 1 :(得分:0)
我假设名为cache
的变量实际上是thing
。然后,另一个答案是对的。默认情况下,参数使用等于匹配器。你可能还没有在Ball
上定义等号。
我做了不同的实现,以展示如何在不添加equals
方法的情况下解决此问题。
关于代码的一些评论:
expectLastCall
没有必要。默认情况下为void方法首先是固定代码:
public class Things {
List<Ball> ballList = new LinkedList<>();
public void addBall(Ball b){
ballList.add(b);
}
}
public class A {
private Things field;
public A(Things field){
this.field = field;
}
public void add(int size){
field.addBall(new Ball(size));
}
}
我已将getSize
添加到Ball
以获得实际的示例。
public class Ball {
private final int size;
public Ball(int size) {
this.size = size;
}
public int getSize() {
return size;
}
}
最后,TestA
public class TestA {
private Things thing;
private A a;
@Before
public void setUp() {
thing = createMock(Things.class);
a = new A(thing);
}
@Test
public void addTest(){
// You should keep only one of these examples
// 1. You don't care about checking `345`. You just want to make sure there is a call. `anyObject` is exactly what you need
thing.addBall(anyObject());
// 2. You want to expect a `Ball` with `345`
thing.addBall(cmp(new Ball(345), Comparator.comparingInt(Ball::getSize), LogicalOperator.EQUAL));
// 3. You prefer a simpler check possibly on many attributes. Just capture the `Ball` passed in parameter and check after if it contains what you want
Capture<Ball> capture = Capture.newInstance();
thing.addBall(capture(capture));
// Now the original code
replay(thing);
a.add(345);
verify(thing);
// Assert on the capture is you used solution #3
assertEquals(345, capture.getValue().getSize());
}
}