본문은 야곰 아카데미 커리어 스타터 캠프를 통해 학습한 내용을 회고한 글입니다.
유닛 테스트 Unit Test
What is Unit Test?
유닛 테스트란, 유닛 단위로 진행되는 테스트를 말한다. 하나의 함수나 메서드의 단위로 독립적으로 진행된다. 내가 구현한 기능이 제대로 작동하는지를 검증하는 절차이다. 이 테스트는 개발자에 의해 진행되기도 하지만 독립적인 tester에 의해서 진행되기도 한다.
Why we need Unit Test?
빠른 리팩토링 반영과 빠른 테스트 진행
코드의 확장이나 리팩토링시 안정성을 확보한 채 대응 가능
How can I implement Unit Test?
예상값과 결과값을 비교하는 형태로 주로 진행이 된다. given-when-then의 단계를 거친다.
- given: 테스트를 준비하기 위해 필요한 value들을 초기화 및 입력하거나 정의
- when: given 단계에서 준비한 value를 활용해 실제 테스트 코드 실행
- then: XCTest 함수를 이용해 결과를 확인하는 테스트 진행
XCT함수에는 다음과 같은 것들이 있다.
XCTAssertFalse: 매개변수로 들어온 값이 false인지 확인을 해준다.
func test_isValidLottoNumbers호출시_6개보다적은숫자입력했을때_False를반환하는지() {
//given
let input = [3, 6, 9]
//when
let result = sut.isValidLottoNumbers(of: input)
//then
XCTAssertFalse(result)
}
XCTAssertTrue: 매개변수로 들어온 값이 true인지 확인을 해준다.
func test_isValidLottoNumbers호출시_중복된숫자없이_6개를입력했을때_True를반환하는지() {
//given
let input = [3, 6, 9, 12, 15, 18]
//when
let result = sut.isValidLottoNumbers(of: input)
//then
XCTAssertTrue(result)
}
XCTAssertEqual: 두 가지의 매개변수가 일치하는지 확인을 해준다.
func test_countMatchingNumber호출시_0개의숫자가맞은경우_0을반환하는지() throws {
//given
let user = [3, 6, 9, 12, 15, 18]
let winner = [2, 4, 13, 14, 23, 24]
//when
let result = try sut.countMatchingNumber(user: user, winner: winner)
//then
XCTAssertEqual(result, 0)
}
XCTAssertThrowsError: 에러를 던지고 있는지 확인을 해준다.
func test_countMatchingNumber호출시_isValidLottoNumbers가False일경우_에러를throw하는지() throws {
//given
let user = [3, 6, 9, 12, 15, 18, 21]
//when
if sut.isValidLottoNumbers(of: user) == false {
//then
XCTAssertThrowsError(try sut.countMatchingNumber(user: user, winner: sut.makeRandomLottoNumbersArray()))
}
}
이 외에도 여러가지 XCTest함수들이 있긴 하다.
FIRST원칙
좋은 유닛테스트를 진행하기 위해서는 FIRST원칙을 따라야한다.
- Fast: 테스트는 빠르게 동작해야한다.
- Independent/Isolated: 각각의 테스트는 독립적이어야한다.
- Repeatable: 언제 어디서나 같은 결과가 반복되어야한다.
- Self-Validating: 성공/실패에 대해 스스로 검증 가능해야한다.
- Timely: 실제 코드를 구현하기 직전에 구현해야한다.
TDD
FIRST원칙에 따르면 유닛테스트는 실제 코드가 구현되기 직전에 구현되어야한다. 이러기 위해서는 테스트를 작성하면서 코드를 구현해야한다. 이런 방법론을 TDD(Test-Driven Development)라고 한다. TDD는 다음과 같은 사이클을 가진다.
RED: 개발하고 싶은 것을 생각해보며 테스트를 구현해본다. 당연히 테스트하고자하는 코드가 존재하지 않기때문에 그 테스트는 실패할 수밖에 없다.
GREEN: 어떻게 그 테스트를 통과할지 생각해보며 코드를 구현해본다.
REFACTOR: 어떻게 구현된 것을 발전시킬지 생각해보며 리팩토링 한다. 코드와 테스트 모두를 리팩토링한다.
TDD의 장단점
장점
- 안전한 코드 작성 가능
- 유지보수하기 좋은 코드 작성 가능
- 의존성이 낮은 코드 작성 가능
단점
- 개발 속도가 느리다
TDD 작성해보기
우선 두 개의 test를 먼저 작성한다.
func test_빈배열전달시_0을반환하는지() {
//given
let numbers: [Int] = []
//when
let result = sut.addOddNumbers(of: numbers)
//then
XCTAssertEqual(result, 0)
}
func test_3을전달했을때_3을반환하는지() {
//given
let numbers: [Int] = [3]
//when
let result = sut.addOddNumbers(of: numbers)
//then
XCTAssertEqual(result, 3)
}
그리고 이에 맞는 코드를 짜는 것이다.
func addOddNumbers(of numbers: [Int]) -> Int {
if numbers.isEmpty {
return 0
}
var result = 0
for number in numbers {
if number%2 == 1 {
result += number
}
}
return result
}
클로저를 통해서 더 간단하게 만들 수 있다.
func addOddNumbers(of numbers: [Int]) -> Int {
let addOddNumbers = numbers.filter{$0%2 == 1}.reduce(0, +)
return addOddNumbers
}
filter
filter는 데이터를 추출하고자 할 때 사용한다. 기존의 컨테이너에서 내부의 값을 걸러 새로운 컨테이너를 만든다.
func filter(_ isIncluded: (Self.Element) throws -> Bool) rethrows -> [Self.Element]
isIncluded가 허용하는 요소들로 이루어진 배열을 반환한다.
다음과 같이 사용할 수 있다.
let names = ["Rhode", "Christy", "Hyemory", "Gundy", "Jeremy", "KokkilE"]
let shortNames = names.filter{ $0.count <= 6 }
print(shortNames) //["Rhode", "Gundy", "Jeremy"]
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
let dividedByThree = numbers.filter { $0 % 3 == 0 }
print(dividedByThree) //[3, 6, 9, 12, 15, 18]
reduce
reduce는 데이터를 합쳐주기 위해 사용한다. 기존 컨테이너에서 내부의 값을 결합하여 새로운 값을 만든다.
func reduce<Result>(
_ initialResult: Result,
_ nextPartialResult: (Result, Self.Element) throws -> Result
) rethrows -> Result
최종적으로 더해진 값이 반환된다. 시퀀스에 요소가 없으면 initialResult를 반환한다.
다음과 같이 사용할 수 있다.
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let numberSum = numbers.reduce(0) { x, y in
x + y
}
print(numberSum) //55
이렇게도 사용할 수 있다.
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let numberSum = numbers.reduce(0, +)
print(numberSum) //55
참조
https://developer.apple.com/documentation/swift/sequence/filter(_:)
https://developer.apple.com/documentation/swift/array/reduce(_:_:)
'YAGOM CAREER STARTER' 카테고리의 다른 글
[TIL] 20230126: SOLID (0) | 2023.01.28 |
---|---|
[TIL] 20230124: Generics (0) | 2023.01.26 |
[토요스터디A반] 20230121: UML을 바탕으로 코드 작성하기 (0) | 2023.01.23 |
[TIL] 20230119: 데이터전달(델리게이트, 노티피케이션센터) (0) | 2023.01.21 |
[TIL] 20230116: Refactoring with delegation (0) | 2023.01.18 |