如何在不测试同一测试用例中的插入的情况下测试 class 的检索方法?

How to test a the retrieve method of my class without testing the insert in the same testcase?

我正在学习单元测试(采用类似 TDD 的方法)。 我正在创建一个封装集合的 class,它有 3 个方法:

我创建了一个测试:testRetrieveWhenEmpty,它是这样的:

@Test
public void testRetrieveAllDocumentsWhenEmpty() {
    List<String> storedDocs = state.retrieveAllDocs();

    assertNotNull(storedDocs);
    assertEquals(0, storedDocs.size());
}

然后我让它通过了。

现在我想创建一个 testRetrieveAllDocumentsWhenNotEmpty,它应该是这样的:

@Test
public void testRetrieveAllDocumentsWhenNotEmpty() {
    state.store("test") //This is the only api point that I can use to insert things
    List<String> storedDocs = state.retrieveAllDocs();

    assertNotNull(storedDocs);
    assertEquals(1, storedDocs.size());
    assertEquals("test", storedDocs..get(0));
}

但是现在我要实现store方法,所以我创建了下面的测试方法:

@Test
public void testStoreDocument() {
    state.store("test")
    List<String> storedDocs = state.retrieveAllDocs(); //This is the only api point I can use to see the content

    assertNotNull(storedDocs);
    assertEquals(1, storedDocs.size());
    assertEquals("test", storedDocs.get(0));
}

我看到两个问题:

  1. 这些方法是相同的。
  2. 我在每个测试中测试了两种方法,如果存储失败,我会收到一条消息,提示检索有问题。

使用反射会将我的测试绑定到我的实现,我正在努力避免它。 更改界面以进行更好的测试对我的队友来说很难。

您在这些情况下采取什么方法? (这种情况有问题吗?)

其实不需要等于:

testRetrieveAllDocumentsWhenNotEmpty中,您可以添加多个文档然后检查大小,也不需要获取所有单个文档,您需要断言大小是正确的。

此方法断言在非空场景中获取所有文档,如果你可以断言你插入了 3,并且只要 testStoreDocument 存在,你就不会不需要断言文档检索但是是列表大小来知道是否返回了所有。

@Test
public void testRetrieveAllDocumentsWhenNotEmpty() {
    state.store("test1") 
    state.store("test2") 
    state.store("test3") 
    List<String> storedDocs = state.retrieveAllDocs();

    assertNotNull(storedDocs);
    assertEquals(3, storedDocs.size());
}

testStoreDocument中,需要获取文档,不需要断言存储文档的大小。

@Test
public void testStoreDocument() {
    state.store("test")
    List<String> storedDocs = state.retrieveAllDocs(); //This is the only api point I can use to see the content

    assertNotNull(storedDocs);
    assertEquals("test", storedDocs.get(0));
}

您可以尝试将您的观点从编写 "a (set of) tests per method" 更改为您正在测试的 class 的 "a test per useful behaviour"。

如果这个 class 既是 reader 也是数据的写入者,那么在测试检索行为时使用它的插入操作是有意义的,反之亦然。

我会测试无项、一项、多项、有特定项、没有特定项的情况。这些测试也会隐式测试存储方法。

Kevlin Henney 的演讲 programming with GUTs 对此概念提供了很好的解释。

如前所述,尝试以测试场景的方式编写单元测试。每个 reader 都会更好地理解您 class 的用途。因为我们不只是想使用一个方法,我们想用这个方法实现一些东西。

您可以在您的测试名称中表达这一点,例如:当{SomethingHappens}Then{ThisIsExpected} 或 given{情况}应该{BeHandledInThisWay}

您可以创建像 givenStoredDocumentsShouldBeAllReturned 和 whenDocumentIsStoredThenItCanBeRetrieved 这样的测试