안드로이드 프로젝트에서 유닛 테스트에 사용할 만한 Test Frame은 Mockito, PowerMock, Roboletric 정도가 있다. 여기에서는 이 셋의 차이점을 알아보고 언제 무엇을 사용할 것인가를 제안하려 한다.


결론부터 말하면 기본적으로 Mockito를 이용하자.

그리고 Mockito의 제한으로 인해 static method 혹은 private method를 테스트 해야 한다면 PowerMock을 이용하자.

가능하다면 Roboletric은 이용하지 말자.

아래에는 각 툴에 대해 살펴보고 이렇게 결론을 내린 이유를 적어본다.



Mockito


mock 객체를 쉽게 만들 수 있게 해주는 도구들 중에는 EasyMock, jMock, Mockito 등이 있으나 현재는 Mockito가 대세이다. 이것은 구글 트렌드에서 확인할 수 있다.



 

http://kwon37xi.egloos.com/4126439 블로그 링크를 보면,  jMock 과 EasyMock을 비교하는데 결론은 엉뚱하게도 Mockito 였다. 글이 2009년에 작성된 글이라 지금은 크게 의미가 없는 내용이긴 하지만 글 마지막에 왜 Mockito로 트렌드가 바뀌었는지에 대한 힌트를 얻을 수 있다. 


그 이유가 Mockito가 마틴 파울러가 이야기한 Mocks aren't Stubs의 원칙을 지키는 프레임워크이기 때문이라고 한다.

(원문글: http://martinfowler.com/articles/mocksArentStubs.html
번역글: http://so-blog.net/2016/05/09/mock_stub/
http://testing.jabberstory.net/)


그리고 여기에 대해 추가로 '왜 Mockito가 좋은가'에 대해 작성한 글이 있는데
http://kwon37xi.egloos.com/4165915 도 참고하면 좋을 것 같다.


Mockto 사용법에 대해서는
공식문서(영문): http://static.javadoc.io/org.mockito/mockito-core/2.2.7/org/mockito/Mockito.html
혹은 누군가 한글로 정리해 둔 아래 링크를 참고하자.
http://bestalign.github.io/2016/07/08/intro-mockito-1/
http://bestalign.github.io/2016/07/10/intro-mockito-2/


하지만 Mockito에는 몇 가지 제약이 있다. 

(https://github.com/mockito/mockito/wiki/FAQ 의 limitation 항목 참고)

그 중 테스트 케이스를 작성하는 데 가장 문제가 되는 부분이 private method와 static method에 대한 mock 을 만들 수 없는 것이다.


static method에 대한 mock을 제공하지 않는 이유에 대해 Mockito팀은 static method는 object orient 와 dependency injection을 사용하는 것이 좋다는 입장이라 구현하지 않는다고 한다. 만약 레거시 코드의 테스트 케이스 작성에 이용하고 싶다면 PowerMock 같은 툴을 이용하라고 한다. 

(static method 관련해서는 Mockito에도 작업중이라는 메일링 리스트의 답글이 있긴 하다)


private method에 대한 mock을 제공하지 않는 이유에 대해서는 아래와 같이 이야기 한다.
1. 기술적으로 추가 작업이 필요하고
2. protected나 package로 메소드의 접근자를 변경하는 간단한 work-around도 있고
3. 담당할 사람도 부족하고 이미 그것을 구현한 PowerMock이라는 툴도 있다.
4. 마지막으로 private method를 mock으로 만들어야 한다면 그것은 OO 측면에서 뭔가 잘못되어 간다는 신호라는 뜻이다.

(https://github.com/mockito/mockito/wiki/Mockito-And-Private-Methods 참고)

 

 

PowerMock

일반적으로 Mockito의 제약을 해결하기 위해 PowerMock을 이용한다.

다만!!! PowerMock 설명에 따르면 PowerMock은 unit testing 에 대해 전문적인 지식을 가진 사람을 위한 것이고, 익숙하지 않는 개발자에게는 좋은 점보다 나쁜 점이 더 많을 수 있다고 한다. (https://github.com/jayway/powermock)

아마도 객체 지향 원칙을 지키지 않아도 되도록 만든다는 측면이 있어서 그렇다고 생각된다.


그럼에도 불구하고 레거시 코드에 대한 테스트 코드를 작성해야 한다거나, 일정상 OO 측면을 조금 무시하고 작성한 코드에 대한 테스트 코드를 작성하려 할 때 PowerMock을 이용하면 되겠다.


정확하게는 우리가 이용할 클래스는 PowerMockito 클래스이다.
PowerMock은 EasyMock과 Mockito에 새로운 feature를 추가한 것이라 생각하면 되고, 

PowerMock 클래스는 EasyMock 을 기반으로 한 것이고,
PowerMockito 클래스는 Mockito 을 기반으로 한 것이다.

현재의 대새는 Mockito라고 하니 PowerMockito를 주로 이용하면 될 것으로 생각된다.


PowerMockito는 아직 Mockito 2.0 베타버전 기반이기에 Mockito 최신 버전의 기능과 혼용해서 사용할 경우 문제가 발생할 수 있다. (PowerMockito에 Mockito의 새로운 버전을 통합하는 작업이 쉽지는 않은 듯 하여 PowerMockito가 기반으로 삼은 Mockito 버전은 최신 Mockito버전과 다를 수 있으니 Mockito 최신 기능 사용시 주의가 필요하다.)


실제 사용 방법은 아래의 링크에서 확인해 볼 수 있다.


static method mocking 예제 파일:
https://github.com/jayway/powermock/tree/master/modules/module-test/mockito/testng/src/test/java/samples/powermockito/testng/staticmocking


Using PowerMock with Mockick:
https://github.com/jayway/powermock/wiki/mockitousage#a-full-example-of-partial-mocking-of-a-private-method



 

Roboletric

Mockto가 익숙하지 않다면 가능하면 이용하지 말자.
Roboletric을 잘못 이용하여 작성한 테스트 케이스는 실제 테스트 결과를 assertion 하지 않는 Code coverage만 늘어날 것이다.


Roboletric의 기본적인 컨셉은 실제 디바이스에서 해야하는 테스트를 JVM 상에서 테스트 할 수 있도록 해 주는 것이다. 실제 디바이스에서 실행하는 것 보다는 시간적으로 물리적으로 이점이 많지만, 비지니스 로직을 테스트 하기 위해서라면 테스트에 걸리는 시간이  많이 소요되고 결국 Mockito 등의 도움이 없으면 assertion하기 힘들다. 

그리고 테스트 케이스 코드 리뷰를 하다보면 Roboletric으로 테스트를 작성한 테스트 케이스는 타겟 메소드가 아닌 Roboletric 코드에 의존적인 assertion을 하는 경우가 많았다. 비지니스 로직은 가능한 Mockito 만으로 작성하도록 노력하자.


Roboletric을 이용하기에 적절한 테스트는 UI 동작을 테스트 하는데 이용하는 것이다.
http://robolectric.org/ 에서 보여주는 예제를 보고 생각해 보자. 

(http://robolectric.org/writing-a-test/ 도 UI 동작 테스트 예제이다)


하지만 Roboletric 만으로 UI 동작을 테스트 하는 코드를 작성하기에는 Roboletric에 대한 신뢰가 아직 부족한 듯 한다. 즉, 테스트가 실패 했을 때, 테스트 케이스가 문제인지,  나의 코드가 문제인지 Roboletric이 문제인지에 대해 확인이 어렵다는 것이다. 그리고 만들더라도 실제 디바이스와 Roboletric의 동작이 다를 가능성도 있다.


그리고 Android Framework 버전의 업데이트 속도를 바로 따라가지 못한다. 얼마전 까지만 해도 현재 sdk version 21까지만 지원하고 있었다. 그리고 최신 버전의 android support 라이브러리류 또한 문제가 있을 가능성이 높다.


단점만 쭉 적어 놓긴 했는데, Roboletric을 이용하는게 좋을 때도 있다.
특히 단위 테스트가 아닌 UI 동작 테스트 라던가, 멀티쓰레드 코드를 테스트 할 때는 도움이 된다고 하는 듯 하다.


반응형

설정

트랙백

댓글

  • 메모리 2016.11.17 12:00 답글 | 수정/삭제 | ADDR

    안녕하세요 궁금한 정보가 있어서 찾아다니다가 들어오게되었습니다.
    Mockito 를 가지고 unit test 항목들을 구현하는 중인데요.
    기존에 class 자체가 특정 class 를 extends 하는 경우에.. 그걸 어떻게 연결시켜주는지 혹시 아시나요?
    test class 는 무조건 extends TestCase 하고 있는데.. ㅠㅠ;; 자꾸 에러가 나서요.. 뭔가 회피방법이 있는지.. super 쪽에 api를 사용하는건 아니고 그냥 extends 만 되어있는 상황인데 혹시 방법이 있을까요?

    • BlogIcon 아자 2016.11.17 19:29 신고 수정/삭제

      설명을 좀 더 해주실 수 있나요?

      일단 어떤 환경에서 테스트를 실행하는지요?
      그리고 어떤 에러 메시지가 발생하나요?

      또 가능하다면 문제가 발생한 테스트 케이스 소스를 붙여주실 수 있나요?