如何使用Mockito对依赖equals()的抽象类方法进行单元测试?

时间:2017-02-15 12:46:35

标签: java unit-testing mockito

我需要在Java中测试一个抽象类,并且我有一个依赖于equals()来提供结果的方法。

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的{​​{1}}构建进行比较。

为了测试这个,我需要创建一个抽象类的空实现,并使mockito调用两个实现方法的真实方法,并为asCanonical()返回我自己的类。

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());
}

Mockito的一个限制是它不允许模拟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. 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;
    }

哪个错了!应该用equals进行比较。通过引用这样做是不一样的。

当我进入 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()toCanonical()方法应该返回同一个类的实例(而不仅仅是任何类)

     

我想在这里测试基类。只有具体的实现知道如何构建一个实际的规范类(asCanonical())或检查这个类是否等于规范类(asCanonical())。请注意equals()如果它等于自身的规范版本,则返回ITSELF。再次toCanonical()

     

实际的实现是不可变的类。因为它们很多,而且这个代码对于我把它放在基类中的每个人都是一样的。

1 个答案:

答案 0 :(得分:1)

为什么要测试一个抽象类?如果你真的想测试toCanonical方法(不是final,所以你可以稍后覆盖它),你可以实例化一个临时具体类并测试它。这比使用Mockito和其他东西更容易。

即:

@Test
public void myAwesomeTest() {
    // Arrange
    BaseClass test = new BaseClass<String>() {
       // provide concrete implementation
       protected String asCanonical() {
             return "Foo";
       }
    };

    // Act
    String result = test.toCanonical("Bar");

    // Assert

}

一旦简单案例有效,您就可以将baseclass的创建提取到工厂方法即MakeBaseClass(String valueToReturnForAsCanonical并编写更多测试。

如果您处于某些未经测试的代码区域并且您无法在代码中存根零件或创建某些接缝,则使用Spy非常方便。在这种情况下,我认为你可以自己编写样板,而不是依靠Mockito的魔法。

祝你好运!