我需要在Java中测试抽象类,并且我有一个方法依赖于equals()
来提供结果。如何单元测试依赖于equals()与Mockito的抽象类方法?
public abstract class BaseClass<T extends BaseClass<T>> {
public boolean isCanonical() {
return toCanonical() == this;
}
public T toCanonical() {
T asCanonical = asCanonical();
if (equals(asCanonical)) {
//noinspection unchecked
return (T) this;
}
return asCanonical;
}
protected abstract T asCanonical();
}
正如你可以看到toCanonical()
法asCanonical
构建调用抽象方法asCanonical()
比较本身。
为了验证这一点,我需要创建一个空的实现我的抽象类,并调用的Mockito这两个实现的方法实际的方法,并返回我自己的类的asCanonical()。
BaseClass aCanonicalClass;
BaseClass aNonCanonicalClass;
@Mock
BaseClass sut;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
// these are the methods under test, use the real ones
Mockito.when(sut.isCanonical())
.thenCallRealMethod();
Mockito.when(sut.toCanonical())
.thenCallRealMethod();
}
一般来说,如果这不是equals()
方法我只是这样做:
@Test
public void test_isCanonical_bad() {
// test true
Mockito.when(sut.equals(aCanonicalClass))
.thenReturn(true);
Mockito.when(sut.equals(aNonCanonicalClass))
.thenReturn(false);
Mockito.when(sut.asCanonical())
.thenReturn(aCanonicalClass);
Assert.assertTrue(sut.isCanonical());
// test false
Mockito.when(sut.equals(aNonCanonicalClass))
.thenReturn(true);
Mockito.when(sut.equals(aCanonicalClass))
.thenReturn(false);
Mockito.when(sut.asCanonical())
.thenReturn(aCanonicalClass);
Assert.assertFalse(sut.isCanonical());
}
这给这个错误:
org.mockito.exceptions.misusing.MissingMethodInvocationException: when() requires an argument which has to be 'a method call on a mock'. For example: when(mock.getArticles()).thenReturn(articles); Also, this error might show up because: 1. you stub either of: final/private/equals()/hashCode() methods. Those methods *cannot* be stubbed/verified. Mocking methods declared on non-public parent classes is not supported. 2. inside when() you don't call method on mock but on some other object.
的一个局限性的Mockito是,它不”允许模拟equals()
和hashcode()
方法。
作为一种解决方法,当我想测试条件equals() = true
和另一个随机对象时,我只是将其自身传递给我,以便测试条件equals() = false
。
@Test
public void test_isCanonical() {
// test true
Mockito.when(sut.asCanonical())
.thenReturn(sut);
Assert.assertTrue(sut.isCanonical());
// test false
Mockito.when(sut.asCanonical())
.thenReturn(aCanonicalClass);
Assert.assertFalse(sut.isCanonical());
}
但是这个测试通过,即使我改变实现这样:
public T toCanonical() {
T asCanonical = asCanonical();
if (this == asCanonical) {
//noinspection unchecked
return (T) this;
}
return asCanonical;
}
,甚至这样的:
public T toCanonical() {
return asCanonical();
}
这是不对的!应该用平等来比较。这样做的参考是不一样的。
事情变得不可能的,当我到达toCanonical()
方法测试:
@Test
public void test_toCanonical_bad() {
// test canonical
Mockito.when(sut.equals(aCanonicalClass))
.thenReturn(true);
Mockito.when(sut.equals(aNonCanonicalClass))
.thenReturn(false);
Mockito.when(sut.asCanonical())
.thenReturn(aCanonicalClass);
Assert.assertSame(sut, sut.toCanonical());
// test non-canonical
Mockito.when(sut.equals(aNonCanonicalClass))
.thenReturn(true);
Mockito.when(sut.equals(aCanonicalClass))
.thenReturn(false);
Mockito.when(sut.asCanonical())
.thenReturn(aCanonicalClass);
Assert.assertNotEquals(sut, sut.toCanonical());
Assert.assertSame(aCanonicalClass, sut.toCanonical());
}
这当然是不行的,而并没有真正有意义的应用相同的解决方法,因为我只想测试该函数的返回值是asCanonical()
之一:
@Test
public void test_toCanonical() {
// test canonical
Mockito.when(sut.asCanonical())
.thenReturn(sut);
Assert.assertSame(sut, sut.toCanonical());
// test non-canonical
Mockito.when(sut.asCanonical())
.thenReturn(aCanonicalClass);
Assert.assertNotEquals(sut, sut.toCanonical());
Assert.assertSame(aCanonicalClass, sut.toCanonical());
}
两种测试是毫无意义的,因为事实上我不能嘲笑的equals()
结果。
有没有一种方法来测试至少equals()
被称为用我给的对象呢? (窥探它)
是否有任何其他的方式来测试这个?
EDIT: this is a semplification of the actual code I'm working with.
I modified the example code to at least show the
toCanonical()
andasCanonical()
methods are supposed to return instances of the same class (and not just any class)I want to test the base class here. Only the concrete implementation know how to build an actual canonical class (
asCanonical()
) or check if this class is equal to a canonical class (equals()
). And please note thattoCanonical()
return ITSELF if it is equals to the canonical version of itself. Againequals != same
.The actual implementations are immutable classes. And since they are many and this code is the same for everyone i put it in a base class.
我不明白为什么不能创建'BaseClass'的非空实现并将所有必要的测试逻辑放在那里?目前看起来你禁止自己在没有Mockito的情况下进行测试。 – user3707125
这是我实际代码中的简化代码,它尽可能缩小了我提出的问题的范围。我没有'BaseClass'的单个实现,为了测试我的抽象类正在做它应该做什么,我必须测试一个空的实现。如果一个子类想要重写'toCanonical()'是免费的,并且会有自己的测试。 –