JUnit 테스트를 작성하다보면, 간혹 테스트케이스 자체가 너무 복잡해져서
또 다른 코드가 되어 버리고, 관리해야할 대상이 되어 버리고, 분석해야 될 코드가 되어 버린다.
(심지어 취미로 개발하는 게 아니라, 월급을 받으려면 테스트 코드 작성에 대한 시간을 많이 투자하기도 어렵다)
그런 의미에서 테스트는 최대한 가독성 좋고, 심플하게 만들어야 된다고 생각한다.
그런데 간혹 이런 케이스가 발생한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
public class UserBO { @Autowired private UserDAO userDAO; public String getFoo() { if (conditionA) { ... } else if (conditionB) { ... } else { ... } } public String getFoo2() { if (conditionA) { ... } else { ... } } } @RunWith(MockitoJUnitRunner.class) public class UserBOTest { @InjectMocks private UserBO dut = new UserBO(); @Mock private UserDAO userDAO; @Test public void getFooWhenA() { } @Test public void getFooWhenB() { } @Test public void getFooWhenOthers() { } @Test public void getFoo2WhenA() { } @Test public void getFoo2WhenOthers() { } } |
보통은 이렇게 만들게 된다.
간단한 예제라서 그렇지 실제로 쓰일 때는 훨씬 복잡한 경우가 발생한다.
if-less한 프로그램을 지향한다던지, 혹은 작은 클래스로 만들어서 더 분할할 필요도 있겠지만..
그런 것을 모두 감안하더라도, 테스트케이스가 단단해질수록 복잡해져간다.
그래서 아래와 같이 정리해봤다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
@RunWith(Suite.class) @SuiteClasses({FooTest.class, Foo2Test.class}) public class UserBOTest { @RunWith(MockitoJUnitRunner.class) public static class FooTest { @Test public whenA() { } @Test public whenB() { } @Test public whenOthers() { } } @RunWith(MockitoJUnitRunner.class) public static class Foo2Test { @Test public whenA() { } @Test public whenOthers() { } } } |
TestSuite는 원래 있던 기능이지만, 생각보다 쓰이질 않는데.. 위처럼 활용해봤다.
각 메소드를 테스트 코드의 static inner클래스로 매핑해버리면,
컴포넌트의 각 메소드별로 테스트도 가능하고,
특히 메소드네이밍이 간결해진다.
단점은, 각 Runner나 dut, 혹은 필요한 상수를 계속 선언해서 사용하니 조금은(?) 불필요한 코드가 생산된다.
주말에 근무하면서 테스트코드를 만들다가 생각나서, 한번 끄적여본다.