[Swift] Unit Test (의존성 주입)

잡담

Unit Test를 경험해보긴 했지만, Unit Test를 올바른 방식으로 하지 않고 있다고 느꼈어요. 과연 Testable Code라는건 어떤 Code를 Testable하다고 부를까 고민했습니다.

검색을 해본 결과, 해외 블로그 게시글을 보고 원하는 정답을 얻을 수 있었어요. 2년이 넘은 게시글이지만, 확실히 좋은 글이라고 생각하기 때문에 이 부분에 대해서 번역하는 느낌으로 서술해보도록 하겠습니다.

순수 함수, 순수 Class(Pure하다의 의미)

내용에 본격적으로 들어가기에 앞서 개발에서 순수하다라는 의미가 무엇을 뜻하는지 말씀드릴려고 해요.

 // Pure function
func sum(_ num1: Int, _ num2: int) -> Int {
    return num1 + num2
}


// Impure function
var accumulated = 0
func add(_ num: Int) -> Int {
    accumulated = num + accumulated
    return accumulated
}

// Pure class
struct Accumulator {
    var value: Int

    // Still impure function
    func add(_ num: Int) -> Int {
        value = num + value
        return value
    }
}

위 코드를 보시면, 순수 함수와 순수하지 않은 함수를 보실 수 있는데요. 간단하게 설명하자면, 함수나 클래스 모두 외부의 변수나 값에 의존적이면 순수하지 않다고 말합니다.

sum 함수의 경우, 입력받은 파라미터 값으로만 내부에서 연산이 이뤄지고 있습니다. 이런 경우를 순수하다라고 하고, add 함수의 경우, 외부 값인 accumulated의 값을 함수 내부에서 참조해서 처리하고 있습니다.

클래스의 경우, 클래스 외부의 값에 참조가 일어나지 않지만, add 함수의 경우는 순수하지 않다고 말할 수 있습니다.

의존성 주입

이게 Unit Test에서 가장 중요한 개념이라고 생각합니다. 위에서 pure하다라는 건 외부의 값에 의존적이지 않다라는 것을 말씀해드렸죠?

여기서 예시 코드를 보여드리자면,

class A {
  func testA() {
    B().testB()
  }
}

class B {
  func testB() {
    print("B")
  }
}

이런 코드가 있다고 가정해봅시다. 그러면 testA 함수는 pure할까요? 그렇지 않습니다. class B에 의존하고 있기 때문인데요.

이걸 해결하기 위해서 의존성 주입이 필요합니다. 이 코드를 아래와 같이 바꾼다면, testA 함수는 pure하다고 말할 수 있습니다.

 class A {
  func testA(c: C) -> String {
    if c.test() {
      return "성공"
    } else {
      return "실패"
    }
  }
}

protocol C {
func test() -> Bool
}

class B: C {
  let check: Bool
  
  init(check: Bool) {
    self.check = check
  }
  
  func test() -> Bool {
    return check
  }
}

이렇게 변경해주면, 더이상 class B에 의존하지 않게 되고, class B를 상속받은 다른 클래스를 넣어도 class B와는 관계없이 항상 동일한 동작을 수행하는 것이기 때문에 Unit Test가 가능합니다.

만약, class B를 protocol로 추상화해서 testA 함수에서 protocol 타입으로 받는다면, 목업으로 다른 class를 만들어서 Test해보기 좋을 것 같습니다.

let b = B(check: true)
let a = A()
let result = a.testA(c: b)
XCTAssertEqual(result, "성공")

이와같이 Test해볼 수 있습니다. 외부에 의존하지 않고, 값을 파라미터로 주입받음으로써 의존성을 주입해준다!! 이게 가장 중요한 키 포인트입니다.