[iOS] Unit Test Code 작성

김상우·2022년 2월 17일
0

앱 개발에서 Test 란

  • 개발자가 작성한 코드가 의도한 대로 잘 작동하는지 확인하는 과정.
  • 프로젝트 파일의 규모가 커질수록 중요성이 두드러진다.
  • 크게 2가지로 구분할 수 있다.
  1. Unit Test : 특정 함수, 메서드의 동작에 대한 테스트
  2. UI Test : UI 표시 or UI Action 에 대한 테스트.

오늘은 개발중인 앱에서, BDD 기반 Unit Test Code 를 작성해봤다.


XCTest Framework (Unit Test)

공식문서 : https://developer.apple.com/documentation/xctest

테스트 파일은 프로젝트 생성 시 추가하면 자동으로 생성된다.
클래스의 오버라이드 메서드로 여러가지가 있고, 아래 2개가 대표적이다.

  • setUpWithError

각각의 테스트 메서드가 실행되기 전에 행되는 메서드. 클래스의 init 메서드와 비슷한 느낌.

  • tearDownWithError

각각의 테스트 메서드가 종료되고 실행되는 메서드. 클래스의 deinit 메서드와 비슷한 느낌.

  • test 메서드 생성법

XCTestCase 를 상속한 클래스의 메서드에서, 이름의 접두사가 test로 시작하면 test 메서드로 간주된다.
ex) func myFunc() -> func testMyFunc()


Test Method 호출 순서도

ref: https://zdodev.github.io


"No such Module" 에러 해결

  • @testable import 에서 "No such module" 에러가 났다.

프로젝트 정보 -> Build Settings -> Product Module Name 에서 module 확인 -> 그 module name 으로 @testable import 하기 -> 해결

모듈명을 다르게 적어서 생긴 오류였고, 모듈명이 한글인 경우도 오류가 생긴다고 한다.


BDD 방법론 (Given, When, Then)

  • 유닛 테스트 코드를 작성할땐 BDD 방식으로 작성하는 것이 좋다.
    (Behavior Driven Develop : 시나리오 기반 테스트 케이스 작성)
  • 테스트 작성 구조, 흐름은 다음과 같다.
  1. Given (A 의 상태에서)
  2. When (B 가 실행될때)
  3. Then (C 가 발생해야 한다)

[ 나만의 테스트 코드 작성 예시 ]

  • 예를들어, 지금 개발하고 있는 앱은 문자인식 카메라 앱인데, 사진에서 전화번호로 추정되는 것을 인식하면 전화를 건다. 근데 AI 가 '0', 'O', 'o', 'ㅇ' 를 서로 헷갈려하는 경향이 있었다.

-> 그래서 refineElementNumber() 라는 함수를 정의했다. 이 함수는 이 헷갈리는것들을 다 숫자 0으로 간주하고, 파싱된 전화번호 string 을 리턴한다.

  • 그래서
  1. Given ("01o-1234-5678" 이라는 문자를 인식한 상태에서)
  2. When (refineElementNumber() 를 실행했을 때)
  3. 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])
	}
}

테스트 코드 결과


Test Coverage

  • Xcode 프로젝트에서, 몇 %의 코드에 대해서 테스트가 작성되어있는지에 대한 수치
  • 앱의 안정성을 평가하는 기준 중 하나가 될 수 있다.
  • 예를들어, 내 앱의 Test Coverage 가 50%다. 그러면 50% 정도의 코드는 안정성이 보장이 됐다고 판단할 수 있다.
  • 설정법 : 시뮬레이터 아이콘 -> Edit Scheme -> Test -> Options -> Gather Coverage for 체크

느낀점

현재 MVC 패턴으로 개발 중이었다. 개발 마무리 단계에서야 와서 보이는게 있다. 현재 코드 구조에서는 ViewController 가 감당하는 일이 너무 많다.
MVP 패턴에서는 이 문제점을 해결하기 위해 Presenter 를 도입해서 ViewController 의 부담을 덜어주기도 하고, 프로토콜을 기반으로 Test code 를 작성하는데 더 유리할 것 같다. 앱 업데이트를 할 때 MVP 패턴으로 리팩토링 해봐야겠다.

profile
안녕하세요, iOS 와 알고리즘에 대한 글을 씁니다.

0개의 댓글