Unit Test, TDD

Groot·2022년 6월 7일
0

TIL

목록 보기
9/153
post-thumbnail

TIL

🌱 난 오늘 무엇을 공부했을까?

📌 Unit Test

📍 Unit Test란?

  • 컴퓨터 프로그래밍에서 소스 코드의 특정 모듈이 의도된 대로 정확히 작동하는지 검증하는 절차다. 즉, 모든 함수와 메소드에 대한 테스트 케이스(Test case)를 작성하는 절차를 말한다

  • Unit Test first 원칙

    • Fast
    • Isolated/Independent
    • Repeatable
    • Self-vaildating
    • timely
  • Unit Test을 해야하는 이유

    • 테스팅에 대한 시간과 비용을 절감할 수 있다.
    • 새로운 기능 추가 시에 수시로 빠르게 테스트 할 수 있다.
    • 리팩토링 시에 안정성을 확보할 수 있다.
    • 코드에 대한 문서가 될 수 있다.
  • Unit Test의 좋은 방법

    • 1개의 테스트 함수에 대해 assert를 최소화하라
    • 1개의 테스트 함수는 1가지 개념 만을 테스트하라

📍 Unit Test 실습

  • LottoMachine
// LottoMachine
struct LottoMachine {
    func isValidLottoNumbers(of numbers: [Int]) -> Bool {
        guard numbers.count == 6, Set(numbers).count == 6 else {
            return false
        }
        
        for num in numbers {
            guard 1...45 ~= num else {
                return false
            }
        }
        
        return true
    }
    
    func makeRandomLottoNumbersArray() -> [Int] {
        var numberSet: Set<Int> = []
        
        while numberSet.count < 6 {
            let randomNumber = Int.random(in: 1...45)
            numberSet.insert(randomNumber)
        }
        
        return Array(numberSet)
    }
    
    
    func countMatchingNumber(user: [Int], winner: [Int]) throws -> Int {
        guard isValidLottoNumbers(of: user) && isValidLottoNumbers(of: winner) else {
            throw LottoMachineError.invalidNumbers
        }
        
        let winNumbers = user.filter { winner.contains($0) }
        return winNumbers.count
    }
}

enum LottoMachineError: Error {
    case invalidNumbers
}
  • LottoMachineTests
// LottoMachineTests
class LottoMachineTests: XCTestCase {
    var sut: LottoMachine!
    
    override func setUpWithError() throws {
        sut = LottoMachine()
    }

    override func tearDownWithError() throws {
        sut = nil
    }

    //MARK: - isValidLottoNumbers
    func test_isValidLottoNumbers_6개보다_많은입력_False() {
        //given
        let input = [1, 2, 3, 4, 5, 6, 7, 8]
        
        // when
        let result = sut.isValidLottoNumbers(of: input)
        
        // then
        XCTAssertFalse(result)
    }
    
    func test_isValidLottoNumbers_6개보다_적은입력_False() {
        // given
        let input = [1, 2, 3]
        
        // when
        let result = sut.isValidLottoNumbers(of: input)
        
        //then
        XCTAssertFalse(result)
    }
    
    func test_isValidLottoNumbers_입력이_1보다_작을때_false() {
        // given
        let input = [-1, 2, 3, 4, 5, 6]
        
        // when
        let result = sut.isValidLottoNumbers(of: input)
        
        //then
        XCTAssertFalse(result)
    }
    
    func test_isValidLottoNumbers_입력이_45보다_클때_false() {
        // given
        let input = [1, 2, 3, 4, 5, 50]
        
        // when
        let result = sut.isValidLottoNumbers(of: input)
        
        //then
        XCTAssertFalse(result)
    }
    
    func test_isValidLottoNumbers_값이_중복일때_false() {
        // given
        let input = [1, 2, 3, 4, 5, 5]
        
        // when
        let result = sut.isValidLottoNumbers(of: input)
        
        //then
        XCTAssertFalse(result)
    }
    
    func test_isValidLottoNumbers_값이_중복없이_6개입력_true() {
        // given
        let input = [1, 2, 3, 4, 5, 6]
        
        // when
        let result = sut.isValidLottoNumbers(of: input)
        
        //then
        XCTAssertTrue(result)
    }
    
    //MARK: - makeRandomLottoNumbersArray
    func test_makeRandomLottoNumbersArray_6개의_중복없는_숫자반환_true() {
        // given
        let input = sut.makeRandomLottoNumbersArray()
        
        // when
        let result = sut.isValidLottoNumbers(of: input)
        
        // then
        XCTAssertTrue(result)
    }

    //MARK: - countMatchingNumber
    func test_countMatchingNumber_4개의동일한숫자일때_4를반환_true() throws {
        // given
        let user = [1, 2, 3, 4, 5, 6]
        let winner = [3, 4, 5, 6, 7, 8]
        
        // when
        let result = try sut.countMatchingNumber(user: user, winner: winner)
        
        // then
        XCTAssertEqual(result, 4)
    }

}

📍 TTD(테스트 주도 개발)

  • 테스트 코드를 먼저 작성하는 개발 방법론은 테스트 주도 개발(Test-Driven Development, TDD)로 많이 불린다.

  • 테스트 코드를 먼저 작성하는 이유

    • 깔끔한 코드를 작성할 수 있다.
    • 장기적으로 개발 비용을 절감할 수 있다.
    • 개발이 끝나면 테스트 코드를 작성하는 것은 매우 귀찮다. 실패 케이스면 더욱 그렇다.
  • 방법 및 순서
  1. 실패하는 작은 단위 테스트를 작성한다. 처음에는 컴파일조차 되지 않을 수 있다.
  2. 빨리 테스트를 통과하기 위해 프로덕션 코드를 작성한다. 이를 위해 정답이 아닌 가짜 구현 등을 작성할 수도 있다.
  3. 그 다음의 테스트 코드를 작성한다. 실패 테스트가 없을 경우에만 성공 테스트를 작성한다.
  4. 새로운 테스트를 통과하기 위해 프로덕션 코드를 추가 또는 수정한다.
  5. 1~4단계를 반복하여 실패/성공의 모든 테스트 케이스를 작성한다.
  6. 개발된 코드들에 대해 모든 중복을 제거하며 리팩토링한다.

📍 TTD 실습

  • StrangeCalculator
struct StrangeCalculator {
    // TODO: TDD로 정수 타입을 파라미터로 받아, 그 절대값이 짝수이면 절반의 값을 반환하는 메서드 구현하기
    
//    func returnHalfValueIfNumberIsEven(number: Int) -> Int {
//        return 0
//    }
    
//    func returnHalfValueIfNumberIsEven(number: Int) -> Int {
//        return number
//    }
        
//    func returnHalfValueIfNumberIsEven(number: Int) -> Int {
//        if number % 2 == 0 {
//            return number / 2
//        }
//
//        return number
//    }
    
    func returnHalfValueIfNumberIsEven(number: Int) -> Int {
        let result = number % 2 == 0 ? number / 2 : number
        
        return result
    }
}

  • StrangeCalculatorTests
class StrangeCalculatorTests: XCTestCase {
    // TODO: TDD로 정수 타입을 파라미터로 받아, 그 절대값이 짝수이면 절반의 값을 반환하는 메서드 구현하기
    
    var sut: StrangeCalculator!
    
    override func setUpWithError() throws {
        try super.setUpWithError()
        sut = StrangeCalculator()
    }

    override func tearDownWithError() throws {
        try super.tearDownWithError()
        sut = nil
    }

    func test_returnHalfValueIfNumberIsEven_0을입력했을때_0을반환() {
        let input = 0
        let expectation = 0
        
        let result = sut.returnHalfValueIfNumberIsEven(number: input)
        
        XCTAssertEqual(result, expectation)
    }
    
    func test_returnHalfValueIfNumberIsEven_5를입력했을때_5를반환() {
        let input = 5
        let expectation = 5
        
        let result = sut.returnHalfValueIfNumberIsEven(number: input)
        
        XCTAssertEqual(result, expectation)
    }
    
    func test_returnHalfValueIfNumberIsEven_10을입력했을때_5를반환() {
        let input = 10
        let expectation = 5
        
        let result = sut.returnHalfValueIfNumberIsEven(number: input)
        
        XCTAssertEqual(result, expectation)
    }
    
}

출처

profile
I Am Groot

0개의 댓글