선생님, 개발을 잘하고 싶어요.

[테스트] MVVM 테스트 하기 - ViewModel 테스트 본문

개발/android 개발

[테스트] MVVM 테스트 하기 - ViewModel 테스트

알고싶은 승민 2020. 5. 24. 21:11

도입

TDD, 테스트 주도 개발 방법론은 저에게 있어서 하나의 넘어야 할 산처럼 느껴졌습니다.

 

다양한 컨퍼런스에서 들려오는 테스트 코드의 장점,

각종 회사에서 우대 사항으로 내거는 "유닛/통합 테스트 코드 작성 경험"

레거시 코드를 다룰 때마다 나를 반기는 무수한 사이드 이펙트들

 

시중에 많은 테스트 관련 책들이 있고, 훌륭한 책들이 많습니다.

하지만 그 개념을 프로젝트에 녹이기 쉽지 않더군요.

 

그래서 다양한 개인 프로젝트에 테스트 코드를 적용해 보고 느낀 점, 회사에 부분적으로 적용하며 고민한 내용을 공유하려고 합니다.

테스트 책에서 읽은 내용들이 어떻게 MVVM 구조에 녹일 수 있을까 고민하신 분들에게 공감되는 이야기, 실용적인 이야기라면 좋겠네요 😋

다룰 것

  • 안드로이드 테스트에 대해서 설명하지만, 특정 테스트 프레임워크를 다루지 않습니다.
  • MVVM 구조로 진행된 프로젝트에 적용한 과정에서 배운 내용입니다. 기본적으로 MVVM 패턴을 이해하시면 도움이 됩니다.

용어 간단 정리

  • 관심 객체: 테스트 시점에 검증할 객체
  • 외부 객체: 관심 객체의 의존성에 해당하는 객체
  • 모의 객체(Mock): 실제 객체를 모방한 객체, 동일한 인터페이스를 가지지만 실제로 속은 비어는 객체
  • Stub: 모의 객체의 실체를 임의로 정하는 행위

ViewModel을 검증 하기

MVVM 보며 생각하기

MVVM의 요소들 중 우리가 오늘 포스팅에서 테스트 해 볼 요소는 ViewModel입니다.

 

여러분, ViewModel 테스트가 무엇 일까요? 어떻게 테스트하고 계신가요?

 

저는 잘 모르겠군요. MVVM 동작 패턴을 함께 보면서 감을 잡아 봅시다.

안드로이드 프로그램에서 시작점은 무엇 일까요? 바로 사용자의 클릭입니다. (혹은 시스템 시계에 따른 타이머 이벤트 일 수도 있죠)

그래서 MVVM 동작도 사용자의 클릭 부터 알아봅시다.

클릭 받아라.

View는 사용자와 상호 작용 하는 창구입니다. 그래서 사용자의 클릭은 View가 캐치하게 됩니다.

View는 이렇게 캐치한 이벤트를 ViewModel에게 넘겨주게 됩니다.

이벤트 발생은 "원하는 결과"가 있기에 존재합니다.

예를 들어, 사용자가 뉴스 기사 보기 버튼을 눌렀다고 가정해 봅시다. 이 경우 사용자는 "최신 뉴스를 보고 싶다"라는 원하는 바가 있기에 버튼 누르기 이벤트를 발생시킨 거죠.

그러면 우리는 그 목적을 완수하기 위해 프로그램을 만들어야 합니다.

뉴스를 가져오기 위해서 서버의 데이터베이스에 접근하고 싶다고 합시다.

 

마침, 서버 데이터베이스에 접근하는 코드가 Repository에 준비되어 있군요.

데이터 내놔.

 

ViewModel이 Repository에 데이터 요청을 했습니다!

 

Repository는 하드 디스크에서 데이터를 가져올 수도 있고, 메모리에서 가져올 수도 있고, 서버 데이터베이스에서 가져올 수 도 있습니다만

아무튼, ViewModel 입장에선 단지 데이터 요청하는 것으로 끝입니다.

 

남은 건 Repository가 지지고 볶고 데이터를 가져올 때까지 커피 한 잔 하며 기다리는 겁니다 😘

저기 데이터가 넘어오고 있네요 😋

넘어온 데이터를 가지고 ViewModel은 자기 자신의 상태를 변경시킵니다. Repository에서 받아온 뉴스 기사에 따라 ViewModel의 상태 값들을 적절히 변경해 주죠.

 

ViewModel은 이렇게만 하면 됩니다. MVVM에서는 View가 알아서 ViewModel의 상태를 염탐하고, 화면을 최신 상태를 유지할 겁니다.

검증할 것?

그러면 우리가 테스트 코드를 작성할 때 신경써야 하는 건 뭘까요?

 

우리가 테스트할 관심 객체는 ViewModel입니다. 따라서 우리가 검증할 것은 ViewModel이 수행하는 것이 되겠죠.

위의 내용에서 빨간색으로 표시한 내용이, ViewModel이 수행하는(외부 객체 입장에서 볼 때는 지원하는) 기능입니다.

 

따라서 테스트 코드에는 다음 두 가지 내용의 검증이 필요하게 됩니다.

  • 관심 객체(ViewModel)의 상태 변화
  • 외부 객체(Repository)의 함수 호출 여부

살아있는 예제

다시 한번, 최신 뉴스 보기 버튼을 떠올려 봅시다. 이 기능에 대한 테스트 코드를 작성해 봅시다.

 

검증할 것 목록을 보셨다면 눈치챘을 수도 있는데,
ViewModel을 테스트할 때, View는 아무런 상관이 없습니다. 이 점 잠시 생각하고 코드로 들어가 볼까요?

 

우리가 테스트를 작성할 관심 객체는 NewsViewModel이죠? 그 이외의 외부 객체로는 NewsRepository가 있네요.

코드를 한 번 볼까요?

여기서 주의하실 점은 관심 객체는 실제 객체를, 외부 객체는 복잡한 경우 모의 객체를 설정해 주시라는 것입니다.

 

관심 객체는 실제 구현체를 검증하는 것이기 때문에 실제 객체 생성을 해주어야 하지만,

외부 객체는 실제 구현체의 검증이 아니고 인터페이스만 신경쓰면 됩니다. 따라서 외부 객체를 생성하는데 필요한 의존성들이 무가치하고 심지어 초기화 하기 귀찮습니다.

이럴 경우 모의 객체로 생성하면 그런 피곤 한 방에 날려버릴 수 있습니다. (이를 객체를 Mock(목)한다고 합니다.)

 

그런데 이상하죠? 외부 객체가 실제 구현체가 없다면, 관심 객체에서 호출하는 외부 객체 함수의 반환 값은 어떻게 될까요?

저는 모의 객체를 만들 때, 반환 값까지 같이 적어 주는 방법을 선택했습니다. 이를 함수를 Stub(스텁)한다고 합니다.

 

외부 객체의 interface를 구현한 테스트에서 사용할 Mock객체를 봅시다.

 

이제 테스트 코드를 작성할 준비가 끝났습니다. 테스트를 하러 가 볼까요?

테스트 코드 작성 첫 시작은, 관심 객체의 생성과 외부 객체의 모의 객체를 관심 객체에 세팅하는 것입니다.

 

이제 관심 객체의 상태 변화를 테스트해 봅니다.

안녕 친구들!

 

관심 객체의 함수가 호출될 때, 상태가 원하는 값으로 변경되었는지 확인하는 간단한 코드입니다.

관심 객체의 함수 호출을 테스트 코드가 하는 점을 주의 깊게 봐주세요.

View가 사용자 이벤트 시점에 ViewModel의 함수를 호출하는 것과 동일한 동작을 하게 된답니다. (그래서 ViewModel의 트리거 역할인 View가 테스트 코드에서 필요 없는 것이지요.)

이제 외부 객체의 함수를 호출했는가 검증해 봅시다.

 

이를 검증하기 위해서는 Mock 객체의 함수가 호출될 때, 해당 함수의 호출 여부를 체크하는 구현체가 필요한데, 귀찮습니다.

이러한 기능들은 유명 테스트 프레임워크에서 다 제공하는 기능입니다. 저는 Mockito의 verify라는 함수를 사용해서 검증하도록 하겠습니다.

 

newsRepository의 getRecentNews라는 함수가 호출 됐는지 검증하는 코드입니다.

이렇게 작성하고 돌리면, 테스트는 실패합니다.

 

당연하죠. 저희는 아직 ViewModel 코드를 작성하지 않았잖아요!

 

이제 테스트가 돌게 코드를 작성해 주면 됩니다. 조금만 코드를 작성해 봅시다.

 

이제 테스트는 통과하고, 우리는 ViewModel의 테스트 코드를 작성했습니다.

 

이렇게 ViewModel을 검증하고 View에서 검증된 ViewModel을 마구 사용해서 화면을 구성하면 되겠죠?


 

엄청 엄청 간단한 안드로이드 MVVM 테스트 코드 도입이 끝났습니다.

 

이번에 포스팅한 내용은 ViewModel 테스트의 이론적인 내용인데요 :)

실제로 이런 테스트 작업을 도와주는 프레임워크가 상당히 많습니다. 추가로 공부하면 좋을 것 같은 내용들을 링크로 달아 놓을게요 😋

테스트로 즐거운 개발 생활합시다 🏃‍♂️🙇‍♂️

 

보면 좋은 것

 

Given - When - Then 파울러 형님 포스팅: https://martinfowler.com/bliki/GivenWhenThen.html

Mockito 기능 리스트: https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html

드로이드 나이츠 2019 김성일 님 "안드로이드 TDD 적용기" 발표 영상: https://youtu.be/avcKY-_3gus

리팩터링 2판: http://www.yes24.com/Product/Goods/89649360

Comments