본문 바로가기

Android/TDD

[Mockito] Mockito를 사용하여 Unit Test 를 해보자 (feat. Truth + Junit4)

728x90

Truth에 이어서 Mockito를 사용한 Unit Test를 해보았다.

Mockito를 사용하여 Unit test를 하기 위해서는, Mockito 만 사용해도 괜찮지만 이전에 사용했던 Truth와 Junit4를 같이 사용하여 진행할 경우 더욱 폭넓은 unit test를 진행할 수 있는 것으로 보인다.

 

지난번에 작성해 두었던 Unit Test 예제 프로젝트를 사용하여 추가적으로 스터디를 진행해 보았다.


우선,

Mockito 가 무엇인가 알아보자.

 

 

Unit Test 를 도와주는 Mocking Framework

 

아주 간단하다. 

유닛테스트를 원활하게 사용하기 위해 가짜 객체(Mock 객체)를 지원해주는 프레임워크가 Mockito이다.

Mock 객체에 대한 것은 필자가 예전에 간단하게 정리해 둔 글이 있으니 참고 바란다.

https://heegs.tistory.com/16

 

[Mockito] Mock 객체 란?

Mock 이란? 실제 객체를 다양한 조건으로 인해 제대로 구현하기 어려울 경우 가짜 객체를 만들어 사용하는데, 이를 Mock 객체라 한다. Mock 객체가 필요한 경우. 테스트 작성을 위한 환경 구축이 어

heegs.tistory.com

 

Mockito를 사용한 Unit Test 란,

Mock 객체를 만들어서 실제 객체의 껍데기를 사용해 테스트를 진행하는 것으로, 실제 구현과 분리해서 생각할 수 있도록 해준다.

 

여기서 Truth와 Junit4를 함께 사용하는 이유는, Mockito를 사용하는 것은 가짜로 데이터를 만들어 넣어 테스트에 필요한 Mock 객체를 만들어 줄 뿐이기 때문에 Mockito에서 제공하는 함수들로는 많은 종류의 Unit Test를 할 수 없기 때문이다.

Mockito로 Mock 객체를 만들고, 더불어서 Truth, Junit4를 사용하여 Unit Test를 수행한다면 실제 구현된 부분을 건드리지 않고, 넓은 범위에서 Unit Test 가 가능할 것으로 보인다.


그렇다면,

Mockito를 적용하고 사용해보자.

 

Truth 때와 마찬가지로, Module 단위의 Gradle에 라이브러리를 추가해 주면 된다.

 

 

단순히 core 만 추가해 주었을 때도 정상적으로 Mockito를 사용은 가능하다.

 

하지만, Kotlin을 사용하는 것 기준으로 정상적으로 예제를 만들어서 테스트를 실행하려고 하면 다음과 같은 에러가 발생할 수 있다.

 

Mockito cannot mock/spy because :
- final class

 

확인해 보니, kotlin 은 class를 생성할 때 기본적으로 final로 생성이 되기 때문에 해당 문제가 발생하는 것이다.

따라서, 이것을 해결해 주기 위하여

 

 

inline에 대한 항목도 추가해 주었다.

해결을 위하여 여러 개의 글을 확인해 보았을 때 core를 제거하고 inline으로 대체하면 된다.라는 글도 찾아볼 수 있었는데, 필자가 확인해본 결과 core 가 없을 경우엔 다른 오류가 발생하여 둘 다 추가하는 것으로 설정하였다.

 

설정이 끝났으므로

Mockito를 사용해보자.

 

우선, 앞서 Unit Test 글에서도 언급했지만 안드로이드 스튜디오에서 제공하는 테스트는 로컬 테스트와 계측 테스트 2가지가 존재하며, Mockito는 이 두 가지 테스트에서 모두 사용이 가능하다.

여기서 필자는 Truth를 사용했을 때와 마찬가지로 로컬 테스트에서 테스트를 수행하도록 예제를 만들었다.

 

테스트 코드를 작성하기 앞서, Mockito를 사용하기 위하여 별도의 간단한 클래스를 만들어 주었다.

 

 

그 후, 여기서 클래스 이름을 마우스 오른쪽 버튼을 누르게 되면

Show Context Action이라는 옵션을 확인할 수 있는데, 이것을 누르고 Create Test를 눌러서 Test 클래스를 간단하게 생성할 수 있다.

 

 

이처럼 간단하게 테스트 클래스를 만들 수 있는데, 

마지막에 어떤 디렉토리에서 클래스를 만들 것인지 체크하는 부분에서 androidTest 가 아닌 test 경로에 만들어 주어야 로컬 테스트를 진행할 수 있다.


Test Code의 경우, 지금까지 작성했던 테스트 코드와 완전히 동일하다.

 

Junit4의 @Before, @After 어노테이션을 사용하여 테스트 시작 전, 후의 작업을 처리해 주고,

@Test 어노테이션을 사용하여 테스트 코드를 작성해 준다.

 

여기서 우리는 Mockito를 사용했으니 Mock 객체를 만들어서 테스트를 진행해보도록 하겠다.

 

 

lateinit로 객체를 선언해주고, @Before 어노테이션 안에서 mock이라는 객체에 Mock 객체를 생성하여 넣어주었다.

 

Mockito.mock()

 

을 사용하여 간단하게 원하는 클래스의 Mock 객체를 생성해 줄 수 있다.

 

그 후, Stub 인 when을 사용하여 객체의 행동을 직접 설정해주면 된다.

여기서, when 앞 뒤에 있는 ` 는 작은따옴표가 아니라 숫자 1 왼편에 있는 것을 사용해야 한다.

필자는 `를 사용하지 않고 when을 타이핑했을 때 자동으로 완성되는 기능을 사용하는 것이 편했다.

 

Mockito.`when`(mock.getNumber()).thenReturn(222)

 

해당 라인을 보면 thenReturn이라는 함수가 있는데,

mock이라는 객체의 getNumber()로 얻을 수 있는 값을 222로 설정하겠다.라는 의미의 라인이다.

이때, getNumber를 호출하기 위한 매개변수가 있을 경우 매개변수까지 넣어서 선언해 주면 된다.

 

위와 같은 선언을 하면, 실제로 MockSample에 선언된 getNumber 함수가 특정한 값을 return 하게 설정이 되어있어도, 테스트 시에 해당 함수를 호출하게 되면 222라는 설정된 값을 return 하도록 한다.라는 의미가 된다.

 

 

before 어노테이션에서 설정을 했으므로, Test 어노테이션으로 선언한 함수 내에서 Truth를 통해 설정한 값을 확인해 보면 된다.

 

 

MockSample 클래스는 다음과 같이 선언이 되어있지만, 위의 truth를 사용해 값을 확인했을 때는 222, "100"이 맞는 값으로 나오게 된다.

 

thenReturn 외에도 when을 사용했을 때 다양한 함수가 제공되는데,

 

 

이처럼 자동 완성 기능을 사용하여 원하는 함수를 사용하도록 하면 된다.

Truth와 마찬가지로, when을 사용할 때 넣은 매개변수의 Type에 따라서 사용할 수 있는 함수가 다르게 표시되니 참고하면 된다.

 

스터디를 하면서 확인을 해보니, thenAnswer 함수도 상당히 많이 사용하는 것으로 보였다.

 

 

이처럼 중괄호를 사용하여 확장된 범위에서 thenReturn 기능을 사용할 수 있는 것으로 보인다.

it을 사용하여 현재 사용 중인 mock 객체의 parameter 값을 가져와서 사용할 수 있으니, 실제 Unit Test를 사용한다면 thenAnswer를 많이 사용하지 않을까 싶다.


when이라는 Test Stub을 통해 Mock 객체에 원하는 동작을 수행시켰다면,

verify를 통해 Mock 객체에 원하는 상호작용이 있었는지 검증할 수 있다.

 

 

값을 확인하는 Truth의 assertThat과 다르게 Mockito의 verify는 상호작용의 여부만 검증할 수 있다.

위의 코드에서 주석을 보면 알 수 있겠지만, 조건을 추가하여 얼마만큼 호출을 했는지 확인이 가능하다.

 

이곳에서 사용하는 Method는 

 

verify(mock).Method : Method 가 호출되었는가?
verify(mock, times).Method : Method 가 times 번 호출되었는가?
verify(mock, never).Method : Method 가 호출되지 않았는가?
verify(mock, atLeastOnce).Method : Method 가 최소 한번 호출되었는가?
verify(mock, atMost).Method : Method 가 최대 n번 호출되었는가?
verify(mock, timeout).Method : Method 가 지정된 시간 안에 호출되었는가?

 

등이 존재한다.

이것들 외에 추가적으로 사용할 수 있는 메서드는, 가장 하단 주석으로 작성한 것처럼

Mockito. 를 타이핑하였을 때 나오는 자동 완성 메서드 목록을 확인하여 사용하면 된다.


이처럼, 

Mockito에서 제공하는 다양한 메서드를 사용하여 Mock 객체를 만들어 Unit Test를 진행할 수 있으며

Truth와 Junit4 등 다른 Unit Test 라이브러리를 사용하면 넓은 범위에서 Unit Test를 수행할 수 있을 것으로 보인다.

 

예제를 만들 때 사용한 Mockito의 함수는 가장 기본적인 것들만 사용했지만, 자동완성 기능을 통해 사용 가능한 함수들을 확인해보니 굉장히 많은 함수들을 지원하는 것으로 보였다.

추후에 Unit Test를 적용하게 되면 필요한 기능들을 어떤 함수가 제공하는지 확인하여 사용해보는 것이 좋을 것 같다.

 

로컬 테스트 환경이 아닌, 계측 테스트 환경에서도 동일하게 Mockito를 사용하면 되는데,

추후에 모듈러 아키텍처 구조에서 유닛 테스트에서 계측 테스트 환경으로 테스트를 진행해 볼 예정이다.

 

해당 게시글에 사용 된 예제 코드는 Github에 업로드 해두었으니 참고 바란다.

https://github.com/HeeGyeong/UnitTestSample

 

GitHub - HeeGyeong/UnitTestSample

Contribute to HeeGyeong/UnitTestSample development by creating an account on GitHub.

github.com

 

728x90