본 포스팅은 실제로 Unit test를 한 결과와 방법에 대한 글이 아닌 Unit test를 위한 아키텍처 설계에 관한 생각을 담은 글임을 미리 알려드립니다
사이드 프로젝트를 진행하면서 팀의 목표아닌 목표는 Unit test 해보기
였습니다
뭔가 필요성을 느껴서라기보다는 좋다라는 이야기는 어디선가 계속들어왔고 앱자체가 엄청 복잡한 앱이아니었어서 새로운 기술을 적용해보기엔 적합한 시기와 프로젝트 규모라고 생각했습니다
흔한 우리의 프로젝트...
하지만 프로젝트가 단기간에 결과물을 내야하는 특성(2주안에 앱 완성)과 팀원과의 경험치차이가 존재하는 팀 내부 상황에 의해서 시작부터 MVVM을 적용하기에는 약간의 무리가 있었습니다
무조건 MVVM을 사용할 시간이 없으니까 제일간단한 MVC쓰자!
그렇다고 이렇게 생각을 했던것도 아니었습니다
동아리 프로젝트에서는 거의 대부분의 팀 100이면 99는 MVC를 사용한다고 하는데 그런 상황을 따라가기 싫었고 적어도 우리가 MVC를 사용하는 이유에대한 정립은 필요하다고 생각했습니다
저희 앱은 단순히 어떠한 정보를 유저에게 보여주는 앱이었고 user가 뭔가를 입력하거나 정보를 받는 data binding이 거의없는 앱구조를 가지고 있었습니다
user와의 insteraction을 통해 data가 binding된다는 MVVM의 가장큰 장점을 사용할 수가 없는데 MVVM을 도입한다는 선택 자체가 어쩌면 프로젝트의 특성에 비해 과한 선택이 아닐까라는 팀 내부적인 결론을 내리게 되었습니다
다만 ViewController가 Massive해질수있다는 점에는 공감을 해서 적어도 View를 최대한 Component화 해서 최대한 Massive하지 않게 하기로 결정을 내렸습니다
여기까지가 프로젝트에 들어가서 적어도 MVC패턴의 앱을 완성했을때까지의 팀내부의 공통적인 의견이었습니다
결국 MVC패턴으로 앱을 완성했고 나름의 디자인시스템 구축으로 Massive하지 않게 ViewController를 만들어보기도하면서 프로젝트를 마무리 지었습니다
하지만 사실 MVC를 채택했을때 팀 내부와 외부에서 여러 조언을 구했을때
MVC로는 Unit test하기 쉽지 않을텐데...
라는 이야기를 정말 많이 들었습니다
사실 그때까지만해도 팀 내부에서 내린 결론은 MVC로 Unit test를 해보고
불편함을 피부로 느끼고 나서 MVVM으로 리팩터링을 하자
였습니다
어떤 기술스택에 대해 공부할때 단순히 기술을 사용해보자보다는 우리가 어떤 불편함을 느낀 후에 기술스택을 적용해야
왜 쓰는가?
에 대한 각자만의 원칙이 생길거라고 생각했습니다
여전히 이 문장에 한치의 망설임도 의심도 없지만 Unit test에 대한 내용을 공부하면서 다른 관점의 시각이 생기게 되었습니다
근본적인 질문으로 들어가서 우리는 Unit test를 통해서 알고자하는것이 뭘까요?
질문을 바꿔서 Unit test를 통해서 어떤 결과를 얻어야할까요?
제가 생각하는 이 질문에 대한 답은 내 로직이 맞는가
라고 생각을 했습니다
예시를 한가지 들어보겠습니다
이렇게 두개의 클래스가 있고 내가 검증하고 싶은 로직들이 A라는 클래스내부에 다들어있다고 가정을 해보겠습니다
만약에 B클래스하고 A클래스하고 아무런 관련이 없다고 가정을 해보겠습니다 서로 그냥 아얘다른 아무런 연관이 없는 클래스라면
A클래스를 Unit test해서 문제가 발생한다면 당연히 이렇게 생각을 할겁니다
A클래스 로직에 문제가 있구나?
근데 만약에 A클래스 내부에서 B클래스의 객체를 가지고 있고 메서드를 호출하고 이렇다고 생각을 해보겠습니다
A클래스를 Unit test해서 문제가 발생한다면 100퍼센트 A클래스에서 문제가 생겼다고 확신할수있나요?
B클래스에서 문제가 발생해서 A클래스까지 그 영향이 미치지 않았다고 항상 100퍼센트 확신할 수 있을까요?
아마 절대 아닐겁니다...
Unit test에서 우리가 원하는 결론, 알고자하는 것을 정확하게 알기 위해서는 내가 test하고자하는 객체가 완전히 독립되어있어야합니다
그래서 의존성주입같은 개념을 활용해서 객체간의 결합도를 끊어주려는 시도들을 하게되는겁니다
MVC로 다시 돌아와서 생각을 해보면 MVC라는건 logic이 ViewController안에 있는 모습을 상상하실수있을겁니다
그렇다고 했을때 logic과 ViewController는 독립되어있다고 볼수가없습니다 아무래도 ViewController내부에 logic이 들어있으니까요
그렇다면 ViewController는 어디에 dependency가 있을까요?
import UIkit
결론부터 이야기하자면 UIkit이라는 외부프레임워크에 dependency가 존재합니다
이말은 결국 UIkit으로부터의 기능인 어플리케이션의 life cycle같은 요소(여러 요소들이 있겠지만 그중에하나)들이 logic과 완전히 독립될수가 없다는 생각이 들었습니다
장황하게 주저리 주저리한거같아서 요약을 해보자면
MVC 패턴은 Controller에서 UIKit이라는 외부 프레임워크를 임포트하기 때문에 외부 프레임워크로부터 영향을 받을 수 밖에 없습니다. MVC패턴은 로직과 뷰를 분리할수없는 아키텍처인데 우리가 테스트하고 싶은 로직이 외부프레임으로부터 영향을 받을수밖에없는 객체 내부에서 생성되고, 사용되는 MVC패턴은 testable하지 않은게아닌가라는 생각이 들었습니다
따라서 MVC패턴에서 logic의 성공과 실패가 외부프레임워크로부터 완전히 독립되어서 나온 결과라고 100퍼센트 확신할수가 없는게 아닌가 라는 의문까지 도달하게되었습니다
그 의문점에서 시작해 결국 MVC에서의 로직의 unit test성공 실패여부가 완전히 외부프레임워크로부터 독립되어서 나온 결과라고 확신을 할수가 없을거같다는 결론을 내리게 되었습니다
팀내부에서 결정했던
- 우선 MVC패턴으로 Unit test를 진행해보고
- 불편함을 느끼고 그 불편함을 해결하기 위해서 MVVM으로 리팩터링을하자
라는 순서자체는 애초에 MVC라는 아키텍처패턴이 Unit test를 했을때 우리가 원하는 결과와 유의미함을 가질수있지만 단순히 조금 불편할뿐이라는 가정으로 이런 방식을 채택했는데
방금 느꼈던 의문으로 인해 MVC는 애초에 testable하지 않은 아키텍처가 아닐까 라는 생각을 하게 해주었습니다
MVC가 아닌 MVP(사실 MVP에 관해서는 잘 모릅니다만)와 MVVM 아키텍처의 경우 logic이 ViewController와 독립된 상태에서 logic test가 가능한 특징이있습니다
ViewModel은 imprt UIkit을 하면안된다
라는 이야기도 스터디원한테 들었던 기억이 나네요
이 이야기를 처음들었을때는 애초에 UI관련해서 직접적인 업데이트를 해주는 역할이 아니라 데이터를 바꿔주고 바뀐데이터를 UI적으로 업데이트 할일이 없으니 uikit을 import할 필요가없지라고 생각했었는데 ViewModel의 logic이 애초에 UI(uikit이라는 외부프레임워크)와 완전히 독립시켜야한다는 뜻이었구나라고 이해하게 되었습니다
결론적으로 Unit test를 하기 위해선, 앞서 했던말로 바꿔보자면
unit test의 결과를 의미있게 받아들이고 결과의 신뢰성을 위해서는 testable한 아키텍처에서 unit test를 진행하는 것이 조금더 옳은 방식이라는 결론을 내리게 되었습니다
그리고 외부 프레임워크와의 의존성이 존재할수밖에없는 MVC아키텍처에서는 Unit test를 진행하기에 적합하지 않다는 결론을 내리게되었고
Unit test를 진행하기 위해서 우선 MVVM패턴으로 프로젝트를 리팩터링한 후 Unit test를 진행하기로 했습니다
Unit test를 공부하다가 들었던 의문에서 시작해서 이렇게 결론까지의 제 생각의 흐름을 글로 남기게되었습니다
다른 팀원들과 이러한 관점에 대해 이야기를 나눠보기도 하고 여러 의견과 생각을듣고 내린 결론이지만 저같은 주니어 개발자의 결론인지라 논리적인 허점이 많을수도있고 결론까지 오는 과정에서 고려하지 못한 부분이 당연히 있을수있다고 생각합니다 혹여나 그런부분이있다면 의견을 남겨주시면 감사하겠습니다🥺
그럼 20000!