- 개발자가 작성한 코드가 의도한 대로 잘 작동하는지 확인하는 과정.
- 프로젝트 파일의 규모가 커질수록 중요성이 두드러진다.
- 크게 2가지로 구분할 수 있다.
- Unit Test : 특정 함수, 메서드의 동작에 대한 테스트
- UI Test : UI 표시 or UI Action 에 대한 테스트.
오늘은 개발중인 앱에서, BDD 기반 Unit Test Code 를 작성해봤다.
공식문서 : https://developer.apple.com/documentation/xctest
테스트 파일은 프로젝트 생성 시 추가하면 자동으로 생성된다.
클래스의 오버라이드 메서드로 여러가지가 있고, 아래 2개가 대표적이다.
- setUpWithError
각각의 테스트 메서드가 실행되기 전에 행되는 메서드. 클래스의 init 메서드와 비슷한 느낌.
- tearDownWithError
각각의 테스트 메서드가 종료되고 실행되는 메서드. 클래스의 deinit 메서드와 비슷한 느낌.
- test 메서드 생성법
XCTestCase 를 상속한 클래스의 메서드에서, 이름의 접두사가 test로 시작하면 test 메서드로 간주된다.
ex) func myFunc() -> func testMyFunc()
- @testable import 에서 "No such module" 에러가 났다.
프로젝트 정보 -> Build Settings -> Product Module Name 에서 module 확인 -> 그 module name 으로 @testable import 하기 -> 해결
모듈명을 다르게 적어서 생긴 오류였고, 모듈명이 한글인 경우도 오류가 생긴다고 한다.
- 유닛 테스트 코드를 작성할땐 BDD 방식으로 작성하는 것이 좋다.
(Behavior Driven Develop : 시나리오 기반 테스트 케이스 작성)
- 테스트 작성 구조, 흐름은 다음과 같다.
- Given (A 의 상태에서)
- When (B 가 실행될때)
- Then (C 가 발생해야 한다)
- 예를들어, 지금 개발하고 있는 앱은 문자인식 카메라 앱인데, 사진에서 전화번호로 추정되는 것을 인식하면 전화를 건다. 근데 AI 가 '0', 'O', 'o', 'ㅇ' 를 서로 헷갈려하는 경향이 있었다.
-> 그래서 refineElementNumber() 라는 함수를 정의했다. 이 함수는 이 헷갈리는것들을 다 숫자 0으로 간주하고, 파싱된 전화번호 string 을 리턴한다.
- 그래서
- Given ("01o-1234-5678" 이라는 문자를 인식한 상태에서)
- When (refineElementNumber() 를 실행했을 때)
- Then ("01012345678" 이 잘 리턴되는가)
를 테스트 해봤다.
func test_refineElementNumber() { // 1. given let element: String = "01o-1234-5678" // 2. when let result: sut.refineElementNumber(element) // 3. then XCTAssertEqual(result, "01012345678") }
- 그리고 Array를 사용해서 좀 더 많은 케이스를 테스트 해봤다.
func test_refineElemNumber() { // 1. given let elems: [String] = ["01o-1234-5678", "ㅇ8ㅇ-000-oooo", "01O.1111.2O20"] let answers: [String] = ["01012345678", "0800000000", "01011112020"] // 2. when for i in 0..<elems.count { let refinedElem = sut.refineElemNumber(elems[i]) // 3. Then XCTAssertEqual(refinedElem, answers[i]) } }
- Xcode 프로젝트에서, 몇 %의 코드에 대해서 테스트가 작성되어있는지에 대한 수치
- 앱의 안정성을 평가하는 기준 중 하나가 될 수 있다.
- 예를들어, 내 앱의 Test Coverage 가 50%다. 그러면 50% 정도의 코드는 안정성이 보장이 됐다고 판단할 수 있다.
- 설정법 : 시뮬레이터 아이콘 -> Edit Scheme -> Test -> Options -> Gather Coverage for 체크
현재 MVC 패턴으로 개발 중이었다. 개발 마무리 단계에서야 와서 보이는게 있다. 현재 코드 구조에서는 ViewController 가 감당하는 일이 너무 많다.
MVP 패턴에서는 이 문제점을 해결하기 위해 Presenter 를 도입해서 ViewController 의 부담을 덜어주기도 하고, 프로토콜을 기반으로 Test code 를 작성하는데 더 유리할 것 같다. 앱 업데이트를 할 때 MVP 패턴으로 리팩토링 해봐야겠다.