TDD를 하고 싶으세요? Mock이 도움이 될 겁니다.
JUnit 같은 것으로 테스트 코드를 작성할 때 막히는 것이 한 두 가지가 아닙니다. 이런 경우 도로변에 경찰복 입혀놓은 마네킨처럼 도와주는 녀석이 Mock Object입니다. 오리대마왕님의 Mock에 대한 정리는 TDD를 익히려 노력하시는 분들에게 도움이 될 것입니다.
언제 Mock Object를 써야하나?
정의를 말하기 전에 필요성이 먼저 나와야 흐름이 맞지만, 일단 있는 개념을 알고 가자는 측면에서 정리하는 것이니 용서해주세요.
c2 wiki 의 중간 부분에 Mock Object 를 이용하는 이유가 정리되어 있으니 살펴보자. 같은 페이지에 이에 대한 비판적인 논의가 오가고 있으니 너무 믿지는 말자. 내가 많이 알고 있어서 비판할 수 있는 역량이 된다면 정리해서 올리면 좋겠지만 나도 잘 모르니 일단 그대로 옮기고 본다. 다음과 같은 상황에서 Mock Object를 사용하면 수월하게 테스트의 목적을 달성할 수 있다고 한다.
1. 실제 객체가 비-결정적인(즉, 그때 그때 주변 여건에 따라 다른) 행위를 보인다.
2. 실제 객체에 대한 초기 설정이 까다롭다. (DB 나 네트웍 커넥션 등이 이에 해당하겠지.)
3. 실제 객체의 행위를 재현하기가 어렵다. (특정 네트웍 에러 등. ) -> 1번 이유와 비슷한 듯.
4. 실제 객체 행위가 느리다. (역시 DB 작업이나 네트웍 통신등이 해당할 듯.)
5. 실제 객체가 UI 를 가지고 있거나, UI 그 자체이다.
6. 테스트 과정에서 객체에 질의를 던져야 할 필요가 있는데, 실제 객체는 해당 질의를 처리하지 않는다. 예) 콜백이 호출되었는 가? (이 경우 Mock Object는 실제 객체보다 "더 많은" 기능을 가지게 된다. 이는 Stub가 일반적으로 실제 객체보다 "훨씬 적은" 기능을 갖는 것과 반대이다.)
7. 실제 객체는 대부분 "정상 동작"을 하지만, 아주 가끔 "예외 동작"을 한다. 단위 테스트를 통해서 특정 객체의 "정상 동작"/"예외 동작" 여부와 관계없이 시스템의 나머지 부분은 정상적인 동작을 하는 것을 확인하고자 한다. -> 2번 이유와 비슷한 듯.
8. 아직 실제 객체를 만들지 않았다.
1. real object has non-deterministic behavior
2. real object is difficult to set up
3. real object has behavior that is hard to cause (e.g., network error) (similar to 1)
4. real object is slow
5. real object has (or is) a UI
6. test needs to query the object, but the queries are not available in the real object (e.g., "was this callback called?") (This needs a MockObject that has *more* stuff than the real object; the other cases usually require a stub that is far smaller than the real object).
7. real object acts "normal" most of the time, but once a month (or even less often) it does something "exceptional". We want UnitTests to make sure the rest of the system does the RightThing whether or not the object is acting "normal" or "exceptional". (Is this the same as #2 ?)
8. real object does not yet exist
