Self-shunt 패턴

기본

셀프-션트 패턴은 유닛 테스팅 패턴 중 하나로 TDDBE에 소개되어 있습니다. 이 패턴은 결국 모킹(mocking)을 사용하는데, 그 대상을 Mock 객체가 아닌 TestCase 자체로 만들어 가독성을 높일 수 있습니다.

어떤 물건을 스캐너에 찍으면 물건의 이름과 가격을 표시해 주는 프로그램이 있다고 가정해 보겠습니다. 이 프로그램의 테스트 코드를 짠다면 아래와 비슷할 겁니다.

public class ScannerTest {
@Test
public void scan() throws Exception {
Display display = new Display();
Scanner scanner = new Scanner(display);
scanner.scan();
}
}

위 코드에서 scanner.scan() 메소드를 실행했을 때 아마 display 객체에 읽어들인 물건의 이름과 가격을 넘겨야 할 겁니다. 그런데 display 객체가 데이터베이스 만큼 뭔가 까다롭다던지 아니면 개발이 덜 됐다던지 등의 이유로 실제 클래스를 사용할 수 없다면 테스트를 위해 Mock 객체를 사용해야 합니다.

public class Display { private Item lastItem; public void displayItem(Item item) { lastItem = item; // something do } } 

Mock 객체를 사용하더라도 테스트 코드가 변경될 이유는 없습니다. 그런데 Mock 클래스를 굳이 만들어야 할 필요성이 있는걸까요? 어차피 테스트 용으로만 사용할 텐데 말입니다. Display의 인터페이스만 테스트 케이스에서 구현하면 관련된 코드가 한 눈에 보이니까 더 편하지 않을까요?

public class ScannerTest implements Display { private Item lastItem; @Test public void scan() throws Exception { Scanner scanner = new Scanner(this); final Item conflakes = new Item("Conflakes"); scanner.scan(conflakes); assertEquals(conflakes, lastItem); } @Override public void displayItem(Item item) { lastItem = item; // something do } } 

TDDBE 내용에 의하면 이렇게 추출된 인터페이스의 경우 나중에도 많이 쓰이게 된다고 합니다.

셀프-션트는 협력 객체를 즉시 사용할 수 있는 이점이 있지만 하나의 발판 역할을 할 뿐입니다. 그리고 만약 이 패턴의 몸집이 커지면 오히려 짐이 될 수 있으므로 그 땐 리팩토링 해줘야 합니다.

Reference

http://www.objectmentor.com/resources/articles/SelfShunPtrn.pdf