1. 첫 번째 학습 내용: Unit Test / TDD

TDD (Test-Driven Development) By 켄트 백


코드를 기능단위로 잘 분리를 해야만 테스트를 잘할 수 있음.
→ 작은 실패를 반복해서 원하는 골로 향한다.

리팩터란? 흐름 안에 있는 코드의 모양새를 바꾸는 것

더하기 연산 함수를 실행했을 때 1+1을 더해서 2가 나오는지?
테스트 하면서 확인하는게 테스트 코드!

하나의 메서드 안에 모든 기능 다 때려넣음
그러면 어떤 코드가 문제가 되는지 파악하기 힘듦!

스텍을 가지고 테스트 코드 작성한다.
Pop 메서드를 테스트하고 싶음

스텍은 애초에 비어있기 때문에
push를 한 다음에 pop을 하는 테스트 했음
만약에 push를 못하면 pop도 못함

push라는 메소드에 의존하고 있는 pop 테스트하는 거임
순수하게 pop만 테스트할 수 있는 코드를 작성해야 함

import Foundation

class Queue {
    var arr: Array<String> = []
    func enqueue(_ item: String) -> Array<String> {
        arr.append(item)
        return arr
    }
    func enqueMultipleItems(_ items: Array<String>) -> Array<String> {
        for item in items {
            arr.append(item)
        }
        return arr
    }
    func dequeue() -> Array<String> {
        arr.removeFirst()
        return arr
    }
    func dequeueMultipleItems(num: Int) -> Array<String> {
        for _ in 1...num {
            arr.removeFirst()
        }
        return arr
    }
    func removeAllItem() -> Array<String> {
        arr = [] //  모든 아이템을 지워주려면 그냥 빈 배열로 만들어버리면 된다.
        return arr
    }
}
import XCTest
@testable import queue

class testQueue: XCTestCase {
    var queue: Queue? // queue 프로퍼티는 Queue클래스를 상속받음?
    override func setUpWithError() throws {
        queue = Queue()
        try super.setUpWithError()
    }
    
    override func tearDownWithError() throws {
        try super.tearDownWithError()
    }
    
    func test_enqueue() {
        XCTAssertEqual(queue.enqueue("yun"), ["yun"])
				// Queue 클래스의 enqueue 메소드를 실행해서 yun을 입력했을떄 결과 값이 yun이 제대로 나오는지 테스트
    }
}

테스트 관련 용어

  1. SUT: (System Under Test) : 주요 객체(primary object)
  2. Test Doubles: 오리지널 객체를 사용해서 테스트를 진행하기가 어려울 경우 이를 대신해서 테스트를 진행할 수 있도록 하는 객체를 의미한다.
  3. dummy
  • 더미 객체는 말 그대로 멍청한 모조품, 단순한 껍데기에 해당한다.
  • 단지 인스턴스화된 객체가 필요할 뿐 해당 객체의 기능까지는 필요하지 않은 경우에 사용한다.
  • 따라서 해당 더미 객체의 메소드가 호출됐을 때의 정상 동작은 보장되지 않는다. 보통은 타입 기본값(0, null, false 등)으로 반환값을 만들어주는 선에서 마무리한다.
  1. stub:
  • 더미 객체가 마치 실제로 동작하는 것처럼 보이게 만들어놓은 객체를 의미한다.
  • 더미 객체로 만들어진 인스턴스의 메소드를 호출하면 타입 기본값으로 리턴되거나 아무 일도 일어나지 않는 데 비해 테스트 스텁은 객체의 특정 상태를 가정해서 만들었기 때문에 특정한 값을 리턴하거나 특정 메시지를 출력한다.
  1. Mock:
  • 일반적으로는 조각하기 쉬운 재료를 이용해 추후 만들어질 제품의 외양을 흉내 낸 모조품을 의미한다.
  • 소프트웨어 개발에 있어서 Mock은 모듈의 겉모양이 실제 모듈과 비슷하게 보이도록 만든 가짜 객체다.
  • 우리가 구현을 하는 데 필요하지만 실제로 준비하기엔 여러 어려움이 따르는 대상을 필요한 부분만큼만 채워넣어서 만들어진 객체를 의미한다.
  1. fake:
  • 여러 개의 인스턴스를 대표할 수 있는 경우이거나, 좀 더 복잡한 구현이 들어가 있는 객체를 지칭하는 단어이다.
  • 복잡한 로직이나, 객체 내부에서 필요로 하는 다른 외부 객체들의 동작을 비교적 단순화하여 구현한 객체이다.
  • 결과적으로는 테스트 케이스 작성을 진행하기 위해 필요한 다른 객체들과의 의존성을 제거하기 위해 사용된다.
  1. spy:
  • 테스트에 사용되는 객체에 대해 특정 객체가 사용됐는지, 그리고 그 객체의 예상된 메소드가 정상적으로 호출됐는지 확인해야 하는 상황에서 호출 여부를 몰래 감시하여 기록했다가 요청이 들어오면 해당 기록을 전달한다.
  • 특정 메소드의 정상호출 여부 확인을 목적으로 구현되며, 더미부터 시작해서 페이크 객체에 이르기까지 테스트 더블로 구현된 객체 전 범위에 걸쳐 해당 기능을 추가할 수 있다. 테스트 스파이 객체는 다른 동작을 하면서 스파이 기능까지 하는 경우가 많다.

출처:

"TDD 실천법과 도구" 책 전체를 PDF 공개합니다. https://repo.yona.io/doortts/blog/issue/1

TDD (Test Driven Development) 란? https://velog.io/@sbyeol3/TDD-Test-Driven-Development-란

2. 두 번째 학습 내용: Stack 자료구조 구현

import UIKit

public struct Stack<T> {
    private var elements = [T]()
    public init() {}

    public mutating func push(_ element: T) {
        self.elements.append(element)
    }

    public mutating func pop() -> T? {
        return self.elements.popLast()
    }

    public func peek() -> T? {
        return self.elements.last
    }
    
    public func isEmpty() -> Bool {
        return self.elements.isEmpty
    }
    
    public var count: Int {
        return self.elements.count
    }
}

var myStack = Stack<Int>()
myStack.isEmpty()
myStack.push(1)
print(myStack)
myStack.isEmpty()
myStack.push(2)
print(myStack)
myStack.count
myStack.peek()
myStack.pop()
print(myStack)

출처: https://gimjinging.tistory.com/83

profile
iOS Developer

0개의 댓글