TDD, RxSwift, MVVM을 이용해서 간단한 앱 개발을 해보겠습니다.
TDD(Test Driven Development)를 한다고 하는 것은 기본적으로 로직 코드를 작성하기 전에 테스트 코드를 먼저 작성한다는 것을 의미합니다. 그런데 로직 코드를 작성하기 전에 테스트 코드를 작성한다는 것은 무엇을 의미할까요? 무슨 이점이 있을까요?
예를 들어 add 라는 덧셈을 하는 함수를 작성한다고 가정해 봅시다. TDD를 한다고 했으니, 먼저 add에 대한 테스트 코드를 작성합시다.
코드를 테스트한다는 것은 무엇을 의미할까요? 해당 코드가 원하는 대로 작동하는지 확인한다는 것입니다. 그러면 해당 코드가 원하는 대로 작동하는지 어떻게 확인할 수 있을까요?
여기에서는 add를 작성한다고 했으니, add에 대해 "입력이 a, b 일때, 출력이 a + b 인 값이면 제대로 작동한다"고 할 수 있을 겁니다. 그래서 add에 대한 테스트 코드는 아래와 같은 형태로 작성할 수 있을 겁니다.
if(3 == add(a: 1,b: 2)) {
print("성공")
}
else {
print("실패")
}
XCTAssert를 이용해서 코드를 좀 더 간단하게 표시하면, 아래와 같이 작성할 수 있을 겁니다.
XCTAssert(3 == add(a: 1,b: 2))
이 코드를 실행 시키면, add라는 함수가 없으니 당연히 에러가 나게 됩니다. 이제 add 함수를 아래와 같이 작성합니다.
func add(a:Int, b:Int) -> Int {
return a + b
}
그리고 테스트를 실행시키면 정상적으로 테스트가 통과됩니다.
그럼 여기서, 앞에 테스트 코드를 작성하기 전에 정의했던 "입력이 a, b일때, 출력이 a + b인 값이면 제대로 작동한다"는 무엇을 의미할까요?
이것은 로직 코드가 어떻게 동작해야 하는지를 정의한 문장이 됩니다. (즉, 함수에 대한 스펙(Specification)이죠) 그리고 XCTAssert(3 == add(1,2)) 는 스펙을 코드로 기술한 것입니다.
즉, TDD에서는 테스트 코드를 먼저 작성한다는 작성할 로직 코드에 대한 스펙을 먼저 코드로 정의한다는 것을 의미합니다. 그러면 스펙을 코드로 먼저 정의하고 로직 코드를 작성하게 되면 어떤 이점이 있을까요?
현재로서는 예를 든 코드는 너무 간단해서 별로 이점이 없습니다. 스펙을 코드로 정의해야 하니, 오히려 더 피곤해 보이기만 합니다. 하지만 로직 코드의 양이 많고, 복잡하다면 어떤 일이 어떻게 될까요?
예를 들어 함수 strangeAdd 라는 함수를 작성한다고 가정합시다. stringAdd는 a, b라는 두개의 파라미터를 받는데, a가 3이 아니고 7이 아니며, 짝수가 아닐 때는 a + b인 값을 리턴하고, a가 짝수일 때는 a * b인 값을 리턴한다고 합시다. 그리고 a가 3의 배수일 때는 3 + a * b 인 값을 리턴한다고 하고, a가 7의 배수이면서, b가 8의 배수이면 7 * a + 8 * b 인 값을 리턴한다고 합시다. 그리고 위의 조건이 모두 해당되지 않으면, a + b + 5 인 값을 리턴한다고 합시다.
인단 TDD가 아닌 방식으로 코드를 작성해봅시다.
func stringAdd(a:Int, b:Int) -> Int {
if(0 != a % 2 && 3 != a && 7 != a) {
return a + b
}
else if(0 == a % 2) {
return a * b
}
else if(0 == a % 3) {
return 3 + a * b
}
else if(0 == a % 7 && 0 == b % 8) {
return 7 * a + 8 * b
}
return a + b + 5
}
```