반응형
블로그 이미지
개발자로서 현장에서 일하면서 새로 접하는 기술들이나 알게된 정보 등을 정리하기 위한 블로그입니다. 운 좋게 미국에서 큰 회사들의 프로젝트에서 컬설턴트로 일하고 있어서 새로운 기술들을 접할 기회가 많이 있습니다. 미국의 IT 프로젝트에서 사용되는 툴들에 대해 많은 분들과 정보를 공유하고 싶습니다.
솔웅

최근에 올라온 글

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

카테고리


반응형

지난번에도 Mockito 를 다룬적이 있는데요.

그 때는 다른 블로그에 있는 Mockito 관련 글을 번역해서 공부해 봤습니다.

예제들도 Android 를 중심으로 만들었구요.

 

오늘은 제가 참여하고 있는 Spring Framework에서 jUnit 테스트를 Mockito 를 사용해서 만든 경험을 정리해 보겠습니다.

 

일반적으로 jUnit 테스트 만드는 방법을 웹에서 검색하면 아주 간단한 예제들이 나옵니다.

하지만 실제 프로젝트에서 jUnit 테스트를 만들다 보면 이게 그렇게 간단하지 않거든요.

 

테스트하는 메소드 내에서 다른 메소드를 호출해서 return 값을 받아서 그 다음 일을 진행하기도 하고 또 호출한 메소드 내에서 또 다른 메소드의 호출이 일어나기도 하고요.

 

이럴 경우 Mockito 를 사용하는데 이번에 제가 실제 프로젝트에 참여하면서 경험하고 배운 내용을 정리합니다.

 

Spring Framework에는 Controller - Service - Transaction 이렇게 세개의 Layer로 나눠집니다.

 

Controller 부분은 Client Web 부분과 소통하고 Transaction은 SOA 나 DB 랑 소통합니다.

 

 

 

제가 참여하는 프로젝트의 흐름을 간단히 설명 드리면 Client 웹 브라우저의 form 문을 통해서 Controller에 어떤 데이터가 전달 됩니다. (이 때 세션값들도 받구요.)

그럼 Controller에서는 이 데이터를 기반으로 Bean 을 만들어 Service Layer로 던집니다. 그러면 Service Layer에서는 DTO를 만들어 Transaction으로 패스하고 Transaction에서는 Request를 Web Service 로 보냅니다.

웹 서비스에서는 다른 시스템이나 디비와 소통하면서 Response를 받아 Transaction으로 던져 주고요. Transaction은 이 Response를 가지고 DTO를 만들어서 Service로 던져 줍니다.

그러면 이 Service에서는 이를 다시 Bean으로 만들어 Controller로 패스하구요.

Controller는 이 Bean을 가지고 ModelAndView를 만들어서 Client의 웹 브라우저로 전달해서 그 다음 서비스를 사용자에게 전달합니다.

 

대부분의 중요한 비지니스 로직은 다른 외부 시스템에서 많이 진행 되서 이 자바 콤포넌트 내에서는 크게 비지니스 로직이 있지는 않습니다.

 

여기서 Controller에 있는 한 Method에 대해 jUnit 테스트를 만들게 되면 이 메소드가 Service 의 메소드를 호출하고 이 서비스에서는 다시 Transaction을 호출하고 여기서 다시 웹서비스를 call 해서 거기서 어떤 응답을 받게 되는 모든 과정이 진행됩니다.

 

그래서 단순하게 Controller에 있는 한 Method를 테스트 하려면 이 Service 에 있는 Method를 Call 하는 부분에서 그 return 값을 Mock 하면 됩니다.

 

이를 위해 저는 Mockito를 사용합니다.

 

아래는 지금 주료 사용하는 Mockito의 주요 기능을 정리합니다.

 

@RunWith(MockitoJUnitRunner.class)

처음 Mockito를 사용한다고 선언하는 부분입니다.

프로젝트에서 사용하는 소스코드를 사용할 수 없어서 API 에 있는 예제를 가지고 설명하겠습니다.

 

@RunWith(MockitoJUnitRunner.class)
public class ExampleTest {

    @Mock
    private List list;

    @Test
    public void shouldDoSomething() {
        list.add(100);
    }
}

이 예제는 여기 에 있는 API 문서에 있는 예제입니다.

 

우선 클래스 이름 선언하는 부분 위에 @RunWith(MockitoJUnitRunner.class) 를 선언함으로서 이 클래스에서 Mockito를 사용할 것이라는 것을 알립니다.

 

@Mock

그 다음에 private List list: 위에 @Mock 이라고 돼 있는데요.

이 부분을 Mock 할 거라는 것을 알리는 겁니다.

 

 

@InjectMocks

이 Annotation을 설명하기 위해 다른 예제를 보여드리겠습니다.

이 예제는 여기로 가시면 보실 수 있습니다.

 

public class ArticleManagerTest extends SampleBaseTestCase {

    @Mock private ArticleCalculator calculator;
    @Mock(name = "database") private ArticleDatabase dbMock; // note the mock name attribute
    @Spy private UserProvider userProvider = new ConsumerUserProvider();

    @InjectMocks private ArticleManager manager;

    @Test public void shouldDoSomething() {
        manager.initiateArticle();
        verify(database).addListener(any(ArticleListener.class));
    }
}

public class SampleBaseTestCase {

    @Before public void initMocks() {
        MockitoAnnotations.initMocks(this);
    }
}

 

이렇게 사용하는데요. Mock 한 데이터를 이 @injectMocks 가 선언된 변수에 값을 inject하겠다는 내용입니다.주로 테스트하는 그 메소드에 이 inject 구문을 사용합니다. Mock 한 데이터를 넣어야 하는 곳이 그 메소드일 테니까요.

 

 

다음은 when().then() 구문을 설명할 텐데요.

when(mockedList.get(0)).thenReturn("first");

 

이 코드는 mockedList.get(0) 이라는 부분이 오면 그 return 값으로 first라는 스트링을 넣으라고 하는 명령입니다.

이게 바로 Controller에서 Service Layer에 있는 메소드를 호출 했을 때 이 Service 에 있는 메소드를 실행하지 않고 그 return 값을 mock 할 때 사용하는 구문입니다.

 

제가 참여하는 프로젝트에서는 이런식으로 사용됩니다.

when(service.method(isA(bean.class)).thenReturn(Bean)

 

클래스 이름이나 메소드 이름 그리고 input, return 파라미터 값들은 임의로 정한겁니다.

이 구문을 해석하자면 service 클래스에 있는 method라는 메소드가 호출 되면, 이때 method의 input 값은 bean.class 일 경우 입니다. 하여간 이 method가 호출되면 Bean을 return 하라는 명령입니다.

이전에 Bean을 별도로 생성해서 데이터를 세팅해 놔야 합니다.

 

이상이 제가 참여하는 프로젝트에서 jUnit 테스트를 만들 때 주로 사용하는 Mockito 기능들입니다.

저 위에 예제에서 나왔던 spy()라는 것도 몇군데 사용했는데요. 많이 사용하지는 않았습니다.

 

이 외에 Mockito 명령문은 아니지만 주로 많이 사용했던게 ReflectionTestUtils.setField 인데요.

 

Controller나 Service Layer 등등에서 다른 Layer의 메소드가 아니라 같은 Layer의 utility 클래스나 validator 클래스의 메소드를 호출하는 경우가 많이 있습니다.

 

이 때 이것을 사용했는데요. 다른 클래스의 메소드를 Mock instance로 처리하는 명령어 입니다.

이 기능은 Mockito의 기능이 아니라 Spring Framework의 API 인것으로 알고 있습니다.

 

 

 

반응형