TotT: 스텁이 단위 테스트 속도를 높여줍니다
원문: https://testing.googleblog.com/2007/04/tott-stubs-speed-up-your-unit-tests.html (Translated by Google Gemini)
Michael Feathers는 좋은 단위 테스트의 특징을 “빠르게 실행되고 문제 위치를 파악하는 데 도움이 된다"고 정의합니다. 코드에 데이터베이스 액세스, 다른 서버와의 통신, 시간 의존성 등이 있을 때는 이를 달성하기 어렵습니다.
모듈의 일부 종속성에 커스텀 객체를 대체하여 코드를 철저히 테스트하고, 커버리지를 높이며, 1초 이내에 실행할 수 있습니다. 데이터베이스 오류와 같은 드문 시나리오도 시뮬레이션하여 오류 처리 코드를 테스트할 수도 있습니다.
이러한 “커스텀 객체"를 지칭하는 다양한 용어가 사용됩니다. 용어를 명확히 하기 위해 Gerard Meszaros는 다음 정의를 제공합니다.
- 테스트 더블(Test Double) 은 프로덕션 객체를 대체하는 모든 테스트 객체에 대한 일반적인 용어입니다.
- 더미(Dummy) 객체는 전달되지만 실제로 사용되지 않습니다. 주로 매개변수 목록의 채우기 역할입니다.
- 페이크(Fakes) 는 작동하는 구현을 가지고 있지만 일부 지름길을 사용합니다(예: 메모리 내 데이터베이스).
- 스텁(Stubs) 은 테스트 중에 이루어진 호출에 대해 미리 정해진 응답을 제공합니다.
- 목(Mocks) 은 수신하는 호출과 수신하지 않는 호출의 사양을 형성하는 기대를 가집니다.
예를 들어, IdGetter
클래스의 getIdPrefix()
와 같은 간단한 메서드를 테스트하려면:
public class IdGetter { // Constructor omitted.
public String getIdPrefix() {
try {
String s = db.selectString("select id from foo");
return s.substring(0, 5);
} catch (SQLException e) {
return "";
}
}
}
다음과 같이 작성할 수 있습니다:
db.execute("create table foo (id varchar(40))"); // db created in setUp().
db.execute("insert into foo (id) values ('hello world\\!')");
IdGetter getter = new IdGetter(db);
assertEquals("hello", getter.getIdPrefix());
위 테스트는 작동하지만 실행하는 데 상대적으로 오랜 시간이 걸리고(네트워크 액세스), 신뢰할 수 없으며(DB 머신이 다운될 수 있음), 오류 테스트를 어렵게 만듭니다. 스텁을 사용하면 이러한 함정을 피할 수 있습니다.
public class StubDbThatReturnsId extends Database {
public String selectString(String query) {
return "hello world";
}
}
public class StubDbThatFails extends Database {
public String selectString(String query) throws SQLException {
throw new SQLException("Fake DB failure");
}
}
public void testReturnsFirstFiveCharsOfId() throws Exception {
IdGetter getter = new IdGetter(new StubDbThatReturnsId());
assertEquals("hello", getter.getIdPrefix());
}
public void testReturnsEmptyStringIfIdNotFound() throws Exception {
IdGetter getter = new IdGetter(new StubDbThatFails());
assertEquals("", getter.getIdPrefix());
}
Read other posts