일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- rxjava hot observable
- 멤버변수
- 서비스 vs 쓰레드
- 안드로이드 유닛 테스트 예시
- rxjava disposable
- 안드로이드 레트로핏 crud
- 자바 다형성
- 스택 큐 차이
- android ar 개발
- 서비스 쓰레드 차이
- 안드로이드 라이선스
- ANR이란
- 클래스
- 안드로이드 유닛 테스트
- 스택 자바 코드
- ar vr 차이
- 2022 플러터 설치
- Rxjava Observable
- 안드로이드 유닛테스트란
- android retrofit login
- 플러터 설치 2022
- 객체
- 안드로이드 라이선스 종류
- 안드로이드 레트로핏 사용법
- 큐 자바 코드
- jvm 작동 원리
- jvm이란
- rxjava cold observable
- 안드로이드 os 구조
- 2022 플러터 안드로이드 스튜디오
- Today
- Total
나만을 위한 블로그
[Android] Mocking이란? MockK vs Mockito 본문
안드로이드에서 단위 테스트를 할 때 사용되는 라이브러리 중 하나가 MockK라는 라이브러리다. 공식 홈페이지와 깃허브 레포 주소는 아래에 있다.
https://github.com/mockk/mockk
그럼 이 MockK 라이브러리는 무엇일까? 공식 홈페이지와 깃허브에 설명하는 문구가 없어서 검색해봤다.
https://blog.kotlin-academy.com/mocking-is-not-rocket-science-basics-ae55d0aadf2b
Mocking은 테스트 코드를 읽기 쉽고 유지 관리할 수 있게 만드는 기술이다. MockK는 코틀린에서 Mocking을 훌륭하게 만드는 데 중점을 둔 오픈소스 라이브러리다
즉 Mocking이라는 것을 위해 만들어진 라이브러리라는 뜻이다. 라이브러리에 대해 알아보기 전에 Mocking이 무엇인지 알고 넘어가야 어떤 라이브러리인지 더 잘 이해할 수 있을 듯하다.
mock이란 단어의 사전적 정의는 아래와 같다.
(흉내를 내며) 놀리다, 조롱하다 / 거짓된, 가짜의 / 모의의
여러 뜻이 있는데 합쳐 보면 특정 무언가를 흉내내는 것, 또는 흉내내서 만드는 것이라고 생각된다. 이제 단위 테스트에서의 Mocking(이하 모킹)은 무엇인지 확인해본다.
https://www.telerik.com/products/mocking/unit-testing.aspx
모킹은 테스트 중인 단위에 외부 종속성이 있을 때 단위 테스트에 사용되는 프로세스다. 모킹의 목적은 외부 종속성의 동작이나 상태가 아니라 코드에 집중하고 격리하는 것이다. 모킹에서 종속성은 실제 항목의 동작을 시뮬레이션하는 밀접하게 제어되는 교체 객체로 대체된다. 대체 객체에는 페이크, 스텁, 목의 3가지 주요 유형이 있다
- 페이크(Fakes) : 동일한 인터페이스를 구현하지만 다른 객체와 상호작용하지 않고 실제 코드를 대체하는 객체다. 일반적으로 Fakes는 고정된 결과를 반환하도록 하드코딩된다. 다양한 사용 사례를 테스트하려면 많은 페이크를 도입해야 한다. 페이크를 써서 발생하는 문제는 인터페이스가 바뀌면 해당 인터페이스를 구현하는 모든 페이크들도 수정돼야 한다는 것이다
- 스텁(Stubs) : 스텁은 특정 입력 집합을 기반으로 특정 결과를 반환하는 객체다. 일반적으로 테스트용으로 프로그래밍된 것 외에는 응답하지 않는다
- 목(Mocks) : 스텁의 더 정교한 버전이다. 여전히 스텁과 같은 값을 반환하지만 각 메서드를 몇 번 호출해야 하는지, 어떤 순서로 어떤 데이터를 호출해야 하는지에 대한 기대를 갖고 프로그래밍할 수 있다
https://stackoverflow.com/questions/2665812/what-is-mocking
mock이란 명사를 사전에서 찾아보면 정의 중 하나가 모조품이다. 모킹은 주로 단위 테스트에 쓰인다. 테스트 중인 객체는 다른 (복잡한) 객체에 대한 종속성을 가질 수 있다. 테스트하려는 객체 동작을 분리하려면 다른 객체를 실제 객체의 동작을 시뮬레이트하는 모의 객체로 대체한다. 이는 실제 객체가 단위 테스트에 통합하기 어려운 경우 유용하다. 즉 모킹은 실제 객체의 동작을 시뮬레이션하는 객체를 만드는 것이다...(중략)...목은 스텁과 비슷하지만 테스트는 테스트 중인 객체가 예상대로 목을 호출하는지 확인한다...(중략)
https://dev.to/jameson/fakes-mocks-on-android-well-partner-that-depends-h6n
mock은 내가 받을 것으로 예상되는 호출의 사양을 형성하는 기대치로 사전에 프로그래밍된 객체다
mock에 대해 정리하면 아래와 같다.
- mock은 내가 서버로부터 받을 거라고 예상하고 미리 만들어 두는 예상 응답(객체일 수 있음)이다. mocking은 테스트 시 이러한 mock 객체를 사용하기 위해 만들어 테스트를 진행하는 것이다
- mock은 테스트 시 실제 객체를 사용하면 의존성이 발생하고 시간이 많이 소요되기 때문에, 일관성 있는 결과를 통해 신뢰성 있는 코드를 만들기 위해 사용한다
mock에 대해 알아봤으니 이제 mock을 다루는 라이브러리를 알아본다. 아래는 mock을 사용하는 라이브러리들의 리스트다. 안드로이드의 단위 테스트에 대해 검색하다 보면 봤을 법한 이름들이다.
- MockK
- Mockito
- MockServer
MockServer는 대충 짐작되겠지만, 실제 서버와 통신하는 대신 실제 서버의 mock을 만들어서 네트워크 통신을 수행하기 위한 라이브러리다. 그 위의 2가지 라이브러리와는 조금 다른 라이브러리라고 생각되어 MockServer는 지금은 무시하고 MockK와 Mockito에 대해 알아본다.
MockK는 서두에서 간단하게 알아봤으니 Mockito에 대해 알아본다.
https://en.wikipedia.org/wiki/Mockito
Mockito는 MIT 라이선스에 따라 출시된 자바용 오픈소스 테스트 프레임워크다. 이걸 쓰면 TDD 또는 BDD를 위해 자동화된 단위 테스트에서 테스트 이중 객체(모의 객체)를 만들 수 있다. 프레임워크의 이름, 로고는 모히또(mojito) 음료를 연상시킨다
Mockito를 사용하면 개발자가 사전에 기대치를 설정하지 않고 테스트 중인 시스템의 동작을 확인할 수 있다. mock 객체에 대한 비판 중 하나는 테스트 코드가 테스트 중인 시스템에 긴밀하게 연결돼 있다는 것이다. Mockito는 기대의 사양을 제거해서 기대-실행-검증 패턴을 제거하려고 시도한다. 보일러 플레이트를 줄이기 위한 주석 몇 가지도 제공한다...(중략)
Mockito는 깨끗하고 간단한 API로 멋진 테스트를 작성할 수 있다. Mockito 테스트는 읽기 쉽고 깨끗한 확인 오류를 생성하기 때문에 숙취(hangover)를 주지 않는다. 기능 및 동기에 대해 자세히 알아보라
- 대규모 커뮤니티 스택오버플로우는 Mockito를 자바를 위한 최고의 mock 프레임워크로 선정했다. Mockito가 가장 많은 표를 얻었다는 건 사실이다
- 테스트 도구 뿐 아니라 모든 라이브러리 중 TOP 10 라이브러리다...(중략)
공식 홈페이지야 항상 자신들의 제품을 좋게 말하는 편이니 그렇다 치더라도, 위키백과의 내용은 Mockito에 대해 알아볼 때 참고할 만 하다. Mockito는 이름에서도 유추할 수 있듯 mock을 생성할 때 사용하는 라이브러리다. 기대-실행-검증 패턴은 원문에서 expect-run-verify라고 쓰여 있는데, 최근에는 Given-When-Then 형식을 사용하는 듯하다. 난 서버에서 어떤 응답을 받는다고(Given) 가정했을 때 함수(API 혹은 다른 어떤 것)를 실행한 다음(When), 그리고 나서(Then) 받는 값을 검증한다는 스토리로 이해하고 있다.
추가로 자바용 오픈소스 테스트 프레임워크라고 위키백과에서 설명하지만, 자바로 된 라이브러리들이 으레 그렇듯 Mockito 또한 코틀린으로도 사용할 수 있다. 그러나 그 근본은 자바에서 사용하기 위해 만들어진 것이기 때문에 어노테이션 사용이 필요할 수 있다.
두 라이브러리의 정의를 확인했다면 알 수 있다. MockK과 Mockito는 모두 mock 객체를 만들기 위해 사용하는 라이브러리다. 그럼 두 라이브러리의 차이는 뭐가 있고, 어떤 걸 쓰는 편이 좀 더 나을지 궁금할 수 있다. 이 주제에 대해 다른 사람들은 어떻게 말하고 있는지 알아봤다. 주의할 것은 각 포스팅 작성자의 의견에 매몰되어 무조건 둘 중 하나를 써야겠다 라고 생각하는 것이다. 장점이 있으면 단점이 있듯 비교하고 직접 사용해보기도 하면서 라이브러리의 특징을 파악해 필요할 때, 자신의 프로젝트에 맞는 것을 골라 쓰는 게 가장 좋다고 생각한다.
https://blog.logrocket.com/unit-testing-kotlin-projects-with-mockk-vs-mockito/
MockK, Mockito는 JVM 플랫폼을 대상으로 하는 단위 테스트 작성에 도움되는 라이브러리다. Mockito는 안드로이드 초기부터 사용돼 왔으며 단위 테스트 작성을 위한 mocking 라이브러리가 됐다. Mockito와 MockK는 각각 자바, 코틀린으로 작성됐으며 코틀린과 자바는 상호운용이 가능하므로 같은 프로젝트 안에 존재할 수 있다. 본질적으로 두 라이브러리는 이런 프로젝트에서 상호 교환적으로 사용할 수 있지만...(중략)...다음은 코틀린 프로젝트에서 MockK가 Mockito보다 선호되는 이유를 요약한 것이다
- 코틀린 기능에 대한 최고 수준의 지원
- 깨끗하고 관용적인 코틀린 코드를 작성하기 위한 순수 코틀린 모방 DSL
- final class, method에 대한 mocking 지원
- 코루틴 기본 지원
https://www.reddit.com/r/androiddev/comments/9us0a0/mockk_vs_mockitokotlin/
Mockito-Kotlin은 코틀린과 Mockito 사이에 브릿지를 제공하는 동시에 컴파일러를 만족시키기 위한 몇 가지 해킹을 제공하기 위해 만들어졌다. Mockito는 안정적인 기반을 갖고 있고 수 년 동안 성공한 프로젝트기 때문에 자신감이 있다. 또한 프로젝트를 다른 mock 라이브러리로 마이그레이션하는 게 불가능할 수 있다...(중략)...MockK는 인기를 얻고 있으며 안정성도 확보하고 있으므로 코틀린 우선 솔루션이 좋은 생각이다...(중략)...Mockito-Kotlin은 언뜻 보기에 훌륭한 기능으로 보이는 when {} doReturn을 갖고 있다. 그러나 이것을 과도하게 사용하면 테스트 케이스를 읽을 수 없게 되고 스텁이 프로덕션 동작과 일치하지 않는 경우 해로울 수 있다. 대신 테스트 메서드를 호출할 수 있는 의존성의 테스트 구현을 제공하라...(중략)
https://www.ericthecoder.com/2021/07/20/why-im-switching-from-mockito-to-mockk/
오랫동안 Mockito는 안드로이드용 모킹 프레임워크라고 인식돼 왔지만 최근 코틀린으로 전환하고 채택하면서 MockK가 더 인기를 얻고 있다. MockK는 코틀린 용으로 특별 제작된 mocking 프레임워크다. 코틀린과 더 잘 작동하도록 돕기 위한 Mockito Kotlin과 달리 MockK는 처음부터 코틀린 클래스를 mock하기 위해 구축됐다. 나는 MockK가 Mockito에 부족한 더 나은 테스트 관행을 허용한다는 걸 깨달았다. 이 포스트에서 나는 그것들이 무엇인지 설명할 것이다
- MockK은 기본적으로 답변을 제공하지 않는다
난 이것을 장점으로 말하고 있다. 모의 테스트에 대한 기본 답변에 의존해야 한다면 테스트에 근본적으로 문제가 있다고 생각한다. 물론 절대적으로 필요할 수 있는 상황이 있지만 대부분의 경우에 대해 이야기하겠다. Mockito를 쓰면 기본적으로 모의 클래스(mocked class)의 메서드를 스텁하지 않고, 테스트 중에 호출하면 예외가 발생하지 않고 테스트가 정상 진행된다. 즉 알지 못하는 새 메서드에서 원치 않는 호출을 할 수 있다. 그러나 더 나쁜 것은 완화된(relaxed) 메서드가 의도하지 않은 테스트 시나리오를 도입하고 잘못된 긍정(positives)을 보고할 수 있는 null을 리턴한다는 것이다. 그러나 MockK을 사용하면 아래와 같이 오류가 발생하고 답변이 없다
테스트 중인 메서드에서 getString()을 호출하고 싶지 않다면 아래 방법으로 찾을 수 있다. 따라서 MockK는 테스트에서 접근하는 메서드를 완전히 인식하고 스텁할 것을 권장한다
private val resourceProvider: ResourceProvider = mockk {
every { getString(any()) } returns ""
}
- MockK는 특히 단위 함수(unit functions)를 relax할 수 있게 한다
MockK을 쓰면 모의 클래스의 모든 기능을 완화(relax)할 수 있지만 우리가 원하는 것은 아니다. 그래도 장치 기능만 이완한다? 이제 그것은 다른 이야기다
private val persistentStorageWriter: PersistentStorageWriter = mockk(relaxUnitFun = true)
relaxUnitFun은 리턴타입이 Unit인 해당 모의 함수에 대해 '특정 동작 없음' 생성을 제공한다. 단위 함수에는 다른 타입을 반환하는 함수에서 얻을 수 있는 거짓 null과 달리 반드시 사용해야 하는 리턴타입이 없다. 이것은 테스트를 훨씬 더 간결하고 작성하기 쉽게 만든다...(중략)
- 코루틴 지원
Mockito에는 내장 코루틴 지원이 없으므로 Mockito로 코루틴을 테스트하려면 runBlockingTest를 써야 한다. 디버그 중단점은 단순히 runBlockingTest에서 작동하지 않고 보일러 플레이트기 때문에 이것이 이상적이라고 생각하지 않는다. MockK는 코루틴을 테스트할 때 매우 유용한 coEvery와 coVerify를 갖고 있다. 목적도 분명하다. 모두 suspend function을 위해 작동한다
private val billingInteractor: BillingInteractor = mockk(relaxUnitFun = true) {
coEvery { connectIfNeeded() } returns true
coEvery { getPremiumSkuDetails() } returns SkuDetails("")
}
추가로 MockK을 쓰면 많은 경우 @Before 메서드의 필요성을 제거할 수 있는 모의 생성 안에서 직접 스텁할 수 있다. Mockito도 이 작업을 수행할 수 있다고 생각하지만 쓰이는 걸 확실히 본 적이 없으므로 MockK와 달리 사용할 수 있을 만큼 강력하거나 유연하지 않다고 믿게 됐다
- MockK는 정적 메서드를 mock(모의)할 수 있다
정적 메서드를 모의하는 것이 좋은지는 논쟁의 여지가 있다. 일반적으로 피하는 게 최선이라고 생각하지만 쉽게 피할 수 없는 테스트 케이스가 있다. 안드로이드 코드와 밀접하게 결합된 계측 테스트를 작성하거나 최선의 방법으로 작성하지 않고 정적이며 현재로서는 너무 많은 노력이 필요한 레거시 코드를 테스트할 수 있다. 올바르게 리팩토링하라
MockK는 처음부터 코틀린을 위해 특별 제작됐으며 코루틴 및 정적 자원에서 빛을 발한다. 그리고 위 이유들이 MockK가 Mockito보다 우위에 있다고 말할 수 있는 결정적 이유다...(중략)
자바, 코틀린을 모두 사용하는 경우 이미 가진 지식을 활용하고 팀에 합류하는 사람들의 교육 비용을 줄일 수 있으므로 Mockito를 고수하는 게 좋다. 대부분 또는 전부 코틀린이고 MockK가 지원하는 일부 기능을 테스트하고 싶다면, 가능한 코틀린으로 도구 체인을 사용하려면 MockK를 선택하라
이외에 여러 포스팅에서도 비슷하게 말하기 때문에 MockK와 Mockito를 비교한 내용을 정리한다.
- Mockito는 자바를 기반으로 만들어진 라이브러리라서 자바, 코틀린이 혼용된 프로젝트에서 사용을 고려할 수 있고, 전부 코틀린으로 만들어진 프로젝트라면 MockK 사용을 고려할 수 있다
- MockK가 Mockito에 비해 갖는 장점은 DSL을 통한 가독성 높은 코드 작성이 가능한 것, 코루틴 지원, 정적 함수(코틀린의 companion object function)의 mocking이다
어느 정도 사람들이 어떤 경우에 어떤 라이브러리 사용을 고려하면 좋다고 말하고 있으니 참고해서 자신의 프로젝트에 어떤 mocking 라이브러리를 도입할지 결정하면 되겠다.
'Android' 카테고리의 다른 글
[Android] Parcelize란? (0) | 2023.06.21 |
---|---|
[Android] Espresso Web이란? 웹뷰 UI 테스트 예제 (0) | 2023.04.15 |
[Android] 페이징 라이브러리, Hilt, Flow로 Github API 사용하기 (0) | 2023.04.09 |
[Android] 페이징 라이브러리, Hilt, LiveData로 Github API 사용하기 (0) | 2023.04.09 |
[Android] withContext란? (0) | 2023.04.08 |