원문: https://testing.googleblog.com/2014/04/testing-on-toilet-test-behaviors-not.html (Translated by Google Gemini)


메서드를 작성한 후 메서드가 수행하는 모든 작업을 확인하는 테스트를 하나만 작성하기 쉽습니다. 그러나 테스트와 public 메서드가 1:1 관계를 가져야 한다고 생각하는 것은 해로울 수 있습니다. 우리가 정말로 테스트하고 싶은 것은 동작이며, 단일 메서드가 여러 동작을 나타낼 수 있고, 단일 동작이 때로는 여러 메서드에 걸쳐 있을 수도 있습니다.

전체 메서드를 확인하는 나쁜 테스트를 살펴보겠습니다.

@Test
public void testProcessTransaction() {
  User user = newUserWithBalance(LOW_BALANCE_THRESHOLD.plus(dollars(2)));
  transactionProcessor.processTransaction(
      user,
      new Transaction("Pile of Beanie Babies", dollars(3)));
  assertContains("You bought a Pile of Beanie Babies", ui.getText());
  assertEquals(1, user.getEmails().size());
  assertEquals("Your balance is low", user.getEmails().get(0).getSubject());
}

구매한 품목의 이름을 표시하고 잔액이 부족하다는 이메일을 보내는 것은 두 가지 별개의 동작이지만, 이 테스트는 동일한 메서드에 의해 트리거된다는 이유만으로 이 두 동작을 함께 살펴봅니다. 이러한 테스트는 추가 동작이 계속 추가됨에 따라 시간이 지남에 따라 매우 커지고 유지 관리가 어려워지는 경우가 많습니다. 결국에는 어떤 입력 부분이 어떤 단정(assertion)에 대한 책임이 있는지 파악하기가 매우 어려워질 것입니다. 테스트 이름이 메서드 이름을 직접적으로 반영한다는 사실 자체가 나쁜 징조입니다.

별도의 동작을 확인하기 위해 별도의 테스트를 사용하는 것이 훨씬 더 좋습니다.

@Test
public void testProcessTransaction_displaysNotification() {
  transactionProcessor.processTransaction(
      new User(), new Transaction("Pile of Beanie Babies"));
  assertContains("You bought a Pile of Beanie Babies", ui.getText());
}

@Test
public void testProcessTransaction_sendsEmailWhenBalanceIsLow() {
  User user = newUserWithBalance(LOW_BALANCE_THRESHOLD.plus(dollars(2)));
  transactionProcessor.processTransaction(
      user,
      new Transaction(dollars(3)));
  assertEquals(1, user.getEmails().size());
  assertEquals("Your balance is low", user.getEmails().get(0).getSubject());
}

이제 누군가 새로운 동작을 추가하면 해당 동작에 대한 새로운 테스트를 작성할 것입니다. 각 테스트는 아무리 많은 동작이 추가되더라도 계속해서 집중적이고 이해하기 쉬울 것입니다. 이렇게 하면 새 동작을 추가해도 기존 테스트가 깨질 가능성이 적고, 각 테스트가 하나의 동작만 실행하는 코드를 포함하므로 테스트가 더 명확해져 테스트의 탄력성이 높아집니다.