단위 테스트 2장

이현광·2022년 3월 10일
0

단위 테스트

목록 보기
2/6

단위 테스트란?

  • 고전파
    모든 사람이 단위 테스트와 테스트 주도 개발에 원론적으로 접근하는 방식이기 때문에 '고전'이라고 한다.
  • 런던파
    런던의 프로그래밍 커뮤니티에서 시작되었다.

이 둘의 차이는 5장에서 자세히 다룬다.

'단위 테스트'의 정의

  • 작은 코드 조각을 검증하고
  • 빠르게 수행하고
  • 격리된 방식으로 처리하는 자동화된 테스트

이중에서 격리 문제가 고전파와 런던파를 구분하게 해주는 근원적 차이에 속한다.

격리 문제에 대한 런던파의 접근

런던파에서 격리된 방식이란 테스트 대상 시스템을 협력자에게서 격리하는 것을 말한다.
즉 모든 의존성을 태스트 대역으로 대체해야한다.
동작 자체를 외부 영향과 분리시켜서 테스트 대상 클래스에만 집중할 수 있도록 한다.

이 방식의 이점은 테스트가 실패하면 코드베이스의 어느 부분이 고장 났는지 확실하게 알 수 있다는 것이다.
즉 확실히 테스트 대상 시스템이 고장이 난 것이다.

이렇게 만들었을 때의 부가적인 이점은 더이상 코드베이스를 테스트 하는 방법을 고민할 필요가 없어진다.
클래스가 있으면 클래스에 해당한는 단위 테스트 클래스를 생성해서 테스트를 하면 된다.

코드로 고전파와 런던파의 차이를 한번 알아보자 먼저 고전파의 코드이다.

public void Purchase_fails_when_not_enough_inventory()
{
	//준비
    var store = new Store();
    store.AddInventory(Product.shampoo, 10);
    var customer = new Customer();
    
    //실행
   	bool success = customer.Purchase(store, Product.Shampoo, 15);
    
    //검증 (실패 했기에 수량 변화가 없음)
    Assert.False(success);
    Assert.Equals(10, store.GetInventory(Product.Shampoo));
 }

준비 부분에서는 의존성과 테스트 대상 시스템을 모두 준비하는 부분이다.
실행은 말그대로 테스트하고 싶은 동작으 수행하고 검증에서는 올바르게 수행이 되었는지 확인하는 부분이다.

이 코드는 고전파의 방식이기에 협력자를 대체하지 않고 운영용 인스턴스를 사용한다.
여기서는 Customer 뿐만아니라 Store 둘 다 효과적으로 검사하지만 Customer가 올바르게 작동하더라도 Store 내부에 버그가 있으면 단위 테스트에 실패할 수 있다.
즉 이 테스트에서는 두개가 격리되어있지 않다.

위의 코드를 런던 스타일로 변경을 해보면

public void Purchase_fails_when_not_enough_inventory()
{
	//준비
    var store = new Mock<IStore>();
    storeMock
    	.Setup(x => x.HasEnoughInventory(Product.Shampoo, 5))
        .Return(false)
    var customer = new Customer();
    
    //실행
   	bool success = customer.Purchase(storeMock.Object, Product.Shampoo, 5);
    
    //검증 (실패 했기에 수량 변화가 없음)
    Assert.False(success);
    storeMock.Verify(
    	x => x.RemoveInventory(Product.Shampoo, 5),
        Times.Never);
 }

런던파에서는 준비 단계에서는 Store의 실제 인스턴스를 생성하지 않고 Moq의 내장 클래스를 이용해서 대체한다.
또한 샴푸 재고를 추가하는 대신 HasEnoughInventory() 매서드 호출에 어떻게 응답하는지 목에 직접 정의한다.
더 이상 Store를 사용하는 대신 IStore인터페이스로 목을 만들어 사용한다.

검증 단계 또한 이전과 같이 호출에 대한 결과를 확인하지만 고객이 상점에서 올바르게 했는지 확인하는 방법이 다르다.
이전에는 상점 상태를 검증했지만 지금은 Customer과 Sotore간의 상호 작용을 검사한다.
즉 고객이 상점에서 호출을 올바르게 했는지 확인한다.
호출해야하는 매서드와 호출 횟수까지 검증 가능하다.

런던파의 장점은 더 나은 입자성, 상호 연결된 클래스의 큰 그래프에 대한 테스트 용의성 그리고 테스트 실패 후 버그가 있는 기능을 쉽게 찾을 수 있는 편의성 등을 제공한다.

하지만 몇 가지 문제점은 먼저 테스트 대상 클래스에 대한 초점이 잘못되었다.
테스트는 코드 단위가 아닌 동작 단위로 해야하고 더욱이 코드 조각을 단위 테스트 할 수 없다는 것은 코드 설계에서 문제점이 있다는 징후라는 문제를 가지고 있다.

단위 테스트의 런던파와 고전파

두 파를 나누는 주요 요소

  • 격리 요수 사항
  • 테스트 대상 코드 조각의 구성요소
  • 의존성 처리

고전파와 런던파의 차이점

  • 테스트 주도 개발을 통한 시스템 설계방식
    - 테스트 주도 개발은 테스트에 의존해 프로젝트 개발을 추진하는 소프트웨어 개발 프로세스이다.
    1. 추가해야할 기능과 어떻게 동작해야 하는지를 나타내는 실패 테스트를 작성
    2. 테스트가 통과할 만큰 충분히 코드를 작성한다. 이 단계에서 코드가 깨끗하거나 명쾌할 필요가 없다.
    3. 코드를 리팩토링한다.
  • 과도한 명세 문제

런던파의 방식은 보통 하향식 테스트 주고 개발로 이루어지고 상위 레벨부터 시작하여 모든 클래스를 구현할때까지 클래스 그래프를 다져나간다.
목은 한 번에 한 클래스에 집중할 수 있기 때문에 이 설계 프로세스를 가능하게 한다.

이에 비해 고전하는 실제 객체를 다루어야 하기 때문에 일반적으로 상향식으로 진행을 하게 된다.

느낀점

지금까지 사실 테스트 코드를 작성하면서 고전파와 런던파나 목을 사용하거나 사용하지 않았을 때의 차이점을 모르고 사용했던 것 같다 사실 지금 돌아가서 코드를 다시 봐보면 둘을 섞어서 사용했을 수 도 있다는 생각이 든다... 이제는 둘의 차이점과 이점들을 알고 있으니 어떤 방식의 코드를 사용해야 할지 알 수 있을 것 같다. 이래서,, 이론이 중요하구나 싶다.

profile
cccooodddiiinnngg

0개의 댓글