验证 void 方法调用
verify void method call
我有以下 classes:
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 class 的 add() 方法。更具体地说,我想测试 class Things 的 addBall() 方法是否被调用。
此测试失败说:验证时预期失败:Things.addBall(...):预期:1,实际: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);
}
}
什么是正确的做法?这个测试有什么问题?
我通常使用 Mockito,但这是我的猜测:
当 EasyMock 将您传递到记录阶段的 new Ball(345)
的结果与 a.add(345)
中 new Ball(size)
的结果进行比较时,您正在查看两个完全不同的 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
.
我假设名为 cache
的变量实际上是 thing
。那么,另一个答案是正确的。默认情况下,参数使用 equals 匹配器。您可能还没有在 Ball
.
上定义 equals
我做了不同的实现来展示如何在不添加 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));
}
}
我在 Ball
中添加了 getSize
以提供实际示例。
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());
}
}
我有以下 classes:
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 class 的 add() 方法。更具体地说,我想测试 class Things 的 addBall() 方法是否被调用。 此测试失败说:验证时预期失败:Things.addBall(...):预期:1,实际: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);
}
}
什么是正确的做法?这个测试有什么问题?
我通常使用 Mockito,但这是我的猜测:
当 EasyMock 将您传递到记录阶段的 new Ball(345)
的结果与 a.add(345)
中 new Ball(size)
的结果进行比较时,您正在查看两个完全不同的 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
.
我假设名为 cache
的变量实际上是 thing
。那么,另一个答案是正确的。默认情况下,参数使用 equals 匹配器。您可能还没有在 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));
}
}
我在 Ball
中添加了 getSize
以提供实际示例。
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());
}
}