안녕하세요!
요즘 TDD를 적용해보고 싶어 Unit Test를 학습하고 있는데요,
본격적인 Unit Test 내용은 아직 정리가 안되어서 Unit Test 서론? 같은? 느낌으로
Unit Test에 왜 의존성 주입이 필요한지 이야기해보려고 합니다.
의존성 주입의 필요성
예시 상황으로 회원가입을 하는 함수들을 Unit Test를 통해 검증받고 싶다고 해봅시다.
대충 이런 상황입니다!
그러면 UnitTest 파일에서 ViewModel의 함수들을 알고 있어야 하니까
ViewModel 전체를 소유해야 합니다
그런데 보통 ViewModel에는 다른 기능들도 많이 포함되어 있을 수 있어요
예를 들어 회원 탈퇴 절차도 ViewModel에 있다고 해봅시다.
그럼 테스트를 원하지 않는 코드까지 몽땅 Unit Test가 소유하게 됩니다.
그리고 ViewModel 전체를 소유한 상태에서 코드를 자다 보면 외부의 영향을 받을 수도 있습니다
그러면 정확한 테스트가 이루어지지 않을 수 있어요!
그러면 기능을 Class로 묶고 ViewModel이 해당 클래스를 소유한 형태로 분리하면 어떨까요?
그리고 UnitTest도 해당 Class만 소유해서 테스트하는 거죠
테스트 이름도 SignupUnitTest로 바꿔버립시다!
여기까지 분리된 환경일수록 테스트가 정확하고 안정성이 올라가는 이유를 알아보았습니다.
(하지만 아직 의존성 주입은 등장을 안 했어요!!)
개발을 하다 보면 코드를 수정하는 경우도 있고 다양한 코드들의 동작을 비교해보고 싶을 수도 있습니다
또 네트워킹을 사용하는 코드는 네트워크 상태에 따라서도 테스트 안정성이 달라지죠
아직 이런 다양한 외부 요인에 의해 테스트 안정성이 부족합니다
이때 프로토콜을 통해 의존성을 주입한다면?
다양한 코드를 테스트에 먼저 적용해 볼 수 있고요
(더 TDD스러운 개발을 할 수 있어져요!)
코드를 변경하다 실수도 줄여주고요
네트워킹 요청을 실제로 보내지 않아도 되어서 테스트의 정확성을 올릴 수도 있습니다!
다시 정리하자면 분리된 환경일수록 테스트가 정확하고 안정성이 올라가고
의존성 주입을 통해 객체를 더 분리해서 동작시킬 수 있습니다.
먼 길 돌아왔는데 이제 의존성 주입에 대해 조금 설명하고 끝내려고 합니다.
위 그림에서 저는 의존성 주입을 이렇게 표현했는데요
실제로는 이렇게 구현되어 있습니다.
ViewModel
class ViewModel {
// 인스턴스가 아닌 프로토콜 타입만 명시
private var signupValidator: SignupValidatorProtocol
// 생성자에서 주입
init(signupValidator: SignupModelValidatorProtocol) {
self.signupValidator = signupValidator
}
// 주입된 프로토콜 타입의 함수 사용
func checkSignup(id: String, password: String) -> Bool {
if !signupValidator.checkSignup(firstName: firstName, password: String) {
return
}
}
}
SignupValidatorProtocol
protocol SignupModelValidatorProtocol {
func checkSignup(id: String, password: String) -> Bool
}
SignupValidator
class SignupValidator: SignupValidatorProtocol {
// 예시를 위해 checkSignup 이라는 큰 단위를 사용했지만
// 최대한 테스트 할 함수의 단위를 작게해서 개별로 테스트 하는것이 좋습니다.
// ex) 아이디 값이 4자리보다 작은가? 아이디 값이 12자리를 넘는가?
func checkSignup(id: String, password: String) -> Bool {
var returnValue = true
// 여러 조건들
if 여러 조건들 {
}
return returnValue
}
}
이 그림처럼 Protocol 타입만 명시하고 ViewModel의 인스턴스가 생성될 때
외부에서 SignupValidatorProtocol 타입의 객체를 주입합니다
그러니까 SignupValidatorProtocol 만 따르고 있으면 어떤 객체든 주입할 수 있습니다.
일단 이번 내용은 여기서 끊겠습니다!
네트워킹에 Mock을 사용하는 개념이 어려워서 아직 학습중인데
시간이 된다면 Unit Test 세팅 - 간단한 함수 테스트 - 네트워킹 함수 테스트 순으로 정리해보고 싶네요
혹시 틀린 내용이 있으면 알려주시면 감사하겠습니다!
읽어주셔서 감사합니다