簡體   English   中英

如何使用Mockito對依賴equals()的抽象類方法進行單元測試?

[英]How to unit test an abstract class method that depends on equals() with 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構建進行比較,調用抽象方法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();
    }

這是錯的! 應該用equals進行比較。 通過引用這樣做是不一樣的。

當我到達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() )。 請注意, toCanonical()返回toCanonical()如果它等於自身的規范版本。 equals != same

實際的實現是不可變的類。 因為它們很多,而且這個代碼對於我把它放在基類中的每個人都是一樣的。

你為什么要測試一個抽象類? 如果你真的想測試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的魔法。

祝好運!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM