다음과 같은 기능을 고려하십시오.
function savePeople(dataStore, people) {
people.forEach(person => dataStore.savePerson(person));
}
다음과 같이 사용될 수 있습니다.
myDataStore = new Store('some connection string', 'password');
myPeople = ['Joe', 'Maggie', 'John'];
savePeople(myDataStore, myPeople);
자체 단위 테스트가 있거나 공급 업체에서 제공 한다고 가정 해 봅시다 Store
. 어쨌든 우리는 신뢰 Store
합니다. 그리고 데이터베이스 연결 끊기 오류와 같은 오류 처리는 그 책임이 아니라고 가정합니다 savePeople
. 실제로, 상점 자체 는 어떤 식 으로든 오류를 일으킬 수없는 마법의 데이터베이스 라고 가정 해 봅시다 . 이러한 가정이 주어지면 질문은 다음과 같습니다.
savePeople()
단위 테스트를 해야합니까 , 아니면 그러한 테스트가 내장 forEach
언어 구성체 를 테스트하는 것 입니까?
물론 우리는 모의 dataStore
를 건네고 dataStore.savePerson()
각 사람마다 한 번씩 부름을받을 수 있습니다. 그러한 테스트가 구현 변경에 대해 보안을 제공한다고 주장 할 수 있습니다. 예를 들어, forEach
전통적인 for
루프 로 대체하기로 결정한 경우 또는 다른 반복 방법. 그래서 테스트가 아닌 완전히 사소한. 그럼에도 불구하고 끔찍한 것 같습니다 ...
더 유익한 또 다른 예가 있습니다. 다른 객체 나 함수를 조정하는 것 외에는 아무것도하지 않는 함수를 고려하십시오. 예를 들면 다음과 같습니다.
function bakeCookies(dough, pan, oven) {
panWithRawCookies = pan.add(dough);
oven.addPan(panWithRawCookies);
oven.bakeCookies();
oven.removePan();
}
당신이 생각한다고 가정 할 때, 이와 같은 기능은 어떻게 단위 테스트를해야합니까? 나를 단순히 조롱하지 않습니다 단위 테스트의 모든 종류의 상상하는 것은 어렵다 dough
, pan
그리고 oven
, 다음 방법을 그들이라고 주장합니다. 그러나 이러한 테스트는 함수의 정확한 구현을 복제하는 것 이상을 수행하지 않습니다.
의미있는 블랙 박스 방식으로 기능을 테스트 할 수없는 기능이 기능 자체의 설계 결함을 나타 냅니까? 그렇다면 어떻게 개선 할 수 있습니까?
bakeCookies
예제의 동기를 부여하는 질문에 대해보다 명확하게하기 위해 보다 현실적인 시나리오를 추가하겠습니다.이 시나리오는 레거시 코드에 테스트를 추가하고 리팩토링하려고 할 때 발생하는 시나리오입니다.
사용자가 새 계정을 만들 때 다음과 같은 여러 가지 상황이 발생해야합니다. 1) 데이터베이스에 새 사용자 레코드를 작성해야합니다. 2) 환영 이메일을 보내야합니다. 3) 사기를 위해 사용자의 IP 주소를 기록해야합니다. 목적.
따라서 모든 "새 사용자"단계를 함께 묶는 메소드를 작성하려고합니다.
function createNewUser(validatedUserData, emailService, dataStore) {
userId = dataStore.insertUserRecord(validateduserData);
emailService.sendWelcomeEmail(validatedUserData);
dataStore.recordIpAddress(userId, validatedUserData.ip);
}
이러한 메소드 중 하나라도 오류가 발생하면 오류가 호출 코드까지 버블 링되어 오류가 적절하다고 판단 될 때 오류를 처리 할 수 있습니다. API 코드에 의해 호출되면 오류가 적절한 http 응답 코드로 변환 될 수 있습니다. 웹 인터페이스에 의해 호출되면 오류가 사용자에게 표시되는 적절한 메시지로 변환 될 수 있습니다. 요점은 이 함수 는 발생할 수있는 오류를 처리하는 방법을 모른다는 것입니다.
혼동의 본질은 그러한 기능을 단위 테스트하려면 테스트 자체에서 정확한 구현을 반복해야하며 (메소드가 특정 순서로 모의 객체에 호출되도록 지정하여) 잘못된 것 같습니다.