(왜) 단위 테스트가 종속성을 테스트하지 않는 것이 중요합니까? 된 테스트의 가치를

나는 자동화 된 테스트의 가치를 이해하고 문제가 잘 구체화되어있는 곳이면 어디에서나 좋은 테스트 사례를 만들 수있을 때 사용합니다. 그러나 여기 및 StackOverflow의 일부 사람들 은 종속 장치가 아닌 단위 테스트 강조 합니다. 나는 이점을 보지 못했다.

테스트 종속성을 피하기 위해 조롱 / 스터 빙하면 테스트가 복잡해집니다. 조롱을 지원하기 위해 프로덕션 코드에 인공 유연성 / 감 결합 요구 사항을 추가합니다. (나는 이것이 좋은 디자인을 장려한다고 말하는 사람에 동의하지 않는다. 추가 코드 작성, 의존성 주입 프레임 워크와 같은 것을 도입하거나 코드베이스에 복잡성을 추가하여 실제 사용 사례없이 더 유연하고 플러그 가능 / 확장 가능 / 분리 된 것을 만드는 것은 과도하게 엔지니어링되지 않는다. 좋은 디자인.)

둘째, 의존성을 테스트한다는 것은 모든 곳에서 사용되는 중요한 저수준 코드가 테스트를 작성한 사람이 아닌 다른 입력으로 테스트된다는 것을 의미합니다. 하위 수준의 기능을 모방하지 않고 높은 수준의 기능에 대한 단위 테스트를 실행하여 하위 수준의 기능에서 많은 버그를 발견했습니다. 이상적으로는 하위 수준 기능에 대한 단위 테스트에서 발견되었지만 누락 된 경우는 항상 발생합니다.

이것의 반대편은 무엇입니까? 단위 테스트가 종속성을 테스트하지 않는 것이 정말로 중요합니까? 그렇다면 왜 그렇습니까?

편집 : 데이터베이스, 네트워크, 웹 서비스 등과 같은 외부 종속성 을 조롱하는 것의 가치를 이해할 수 있습니다 (Anna Lear에게 감사드립니다). 내부 종속성 , 즉 다른 클래스, 정적 함수 등을 언급하고 있습니다 . 직접적인 외부 의존성이 없습니다.



답변

정의의 문제입니다. 종속성이있는 테스트는 단위 테스트가 아닌 통합 테스트입니다. 통합 테스트 스위트도 있어야합니다. 차이점은 통합 테스트 스위트가 다른 테스트 프레임 워크에서 실행될 수 있으며 시간이 오래 걸리기 때문에 빌드의 일부가 아닐 수 있다는 것입니다.

우리 제품의 경우 : 단위 테스트는 각 빌드마다 실행되며 몇 초가 걸립니다. 통합 테스트의 일부는 10 분 동안 체크인 할 때마다 실행됩니다. 전체 통합 제품군은 매일 밤 실행되며 4 시간이 걸립니다.


답변

모든 의존성을 가지고 테스트하는 것은 여전히 ​​중요하지만 Jeffrey Faust가 말한 것처럼 통합 테스트 영역에 있습니다.

단위 테스트의 가장 중요한 측면 중 하나는 테스트를 신뢰할 수있게 만드는 것입니다. 통과 테스트가 실제로 문제가 없다는 것을 의미하지 않고 테스트 실패가 실제로 프로덕션 코드의 문제를 의미한다고 믿을 수 없다면 테스트는 그다지 유용하지 않습니다.

테스트를 신뢰할 수있게하려면 몇 가지 작업을 수행해야하지만이 답변에 대해 하나만 집중하겠습니다. 코드를 체크인하기 전에 모든 개발자가 쉽게 실행할 수 있도록 실행하기 쉬운 지 확인해야합니다. “쉽게 실행”은 테스트가 빠르게 실행 되고 테스트를 신속하게 수행 할 수 있도록 구성 또는 설정이 필요하지 않음을 의미합니다 . 이상적으로는 누구나 최신 버전의 코드를 확인하고 테스트를 즉시 실행하여 통과하는 것을 볼 수 있어야합니다.

다른 것 (파일 시스템, 데이터베이스, 웹 서비스 등)에 대한 의존성을 제거하면 구성이 필요하지 않으며, “아, 내가 실패했기 때문에 테스트에 실패했습니다. 네트워크 공유가 설정되어 있지 않습니다. 아, 나중에 실행하겠습니다. ”

일부 데이터로 수행 한 작업을 테스트하려는 경우 해당 비즈니스 로직 코드에 대한 단위 테스트는 해당 데이터를 얻는 방법에 신경 쓰지 않아야 합니다. 데이터베이스와 같은 지원 항목에 의존하지 않고 응용 프로그램의 핵심 논리를 테스트 할 수 있다는 것은 대단합니다. 하지 않으면 빠진 것입니다.

추신 : 나는 테스트 가능성이라는 이름으로 과도하게 엔지니어링 할 수 있다고 덧붙여 야합니다. 애플리케이션을 시험 구동하면이를 완화 할 수 있습니다. 그러나 어쨌든 접근 방식의 구현이 잘못되어 접근 방식의 유효성이 떨어지지는 않습니다. “내가 왜 이러는 걸까?”라는 질문을 계속하지 않으면 어떤 것도 잘못 사용하고 지나칠 수 있습니다. 개발하는 동안.


내부 의존성에 관한 한, 상황이 약간 어둡습니다. 내가 생각하고 싶은 방식은 내가 틀린 이유로 수업을 가능한 한 많이 바꾸지 않기를 원한다는 것입니다. 이와 같은 설정이 있으면 …

public class MyClass
{
    private SomeClass someClass;
    public MyClass()
    {
        someClass = new SomeClass();
    }

    // use someClass in some way
}

나는 일반적으로 어떻게 SomeClass만들어 지는 상관하지 않습니다 . 그냥 사용하고 싶습니다. SomeClass가 변경되어 생성자에 매개 변수가 필요한 경우 내 문제가 아닙니다. 이를 수용하기 위해 MyClass를 변경할 필요는 없습니다.

이제는 디자인 부분 만 다루고 있습니다. 단위 테스트에 관한 한, 나는 또한 다른 수업으로부터 자신을 보호하고 싶습니다. MyClass를 테스트하는 경우 외부 종속성이 없으며 SomeClass가 데이터베이스 연결이나 다른 외부 링크를 도입하지 않았다는 사실을 알고 싶습니다.

그러나 더 큰 문제는 내 메소드의 일부 결과가 SomeClass의 일부 메소드의 출력에 의존한다는 것도 알고 있다는 것입니다. SomeClass를 조롱 / 스터 빙하지 않으면 요구에 따라 입력을 변경할 수있는 방법이 없을 수 있습니다. 운이 좋으면 SomeClass의 올바른 응답을 트리거하는 방식으로 테스트 내 환경을 작성할 수 있지만 그렇게하면 테스트에 복잡성이 생겨 부서지기 쉽습니다.

생성자에서 SomeClass의 인스턴스를 허용하도록 MyClass를 다시 작성하면 (모의 프레임 워크 또는 수동 모의를 통해) 원하는 값을 반환하는 SomeClass의 가짜 인스턴스를 만들 수 있습니다. 나는 일반적으로하지 않습니다 이 경우에 인터페이스를 소개합니다. 그렇게 할 것인지 아닌지는 여러 가지면에서 여러분이 선택한 언어에 의해 지시 될 수있는 개인적인 선택입니다 (예를 들어 C #에서는 인터페이스가 더 많지만 루비에서는 반드시 필요하지 않습니다).


답변

단위 대 통합 테스트 문제 외에도 다음을 고려하십시오.

클래스 위젯은 Thingamajig 및 WhatsIt 클래스에 종속됩니다.

위젯에 대한 단위 테스트가 실패합니다.

어느 수업에 문제가 있습니까?

“디버거를 작동 시키십시오”또는 “찾을 때까지 코드를 읽습니다”라고 대답 한 경우 종속성이 아닌 유닛 만 테스트하는 것이 중요하다는 것을 이해합니다.


답변

프로그래밍이 요리와 같다고 상상해보십시오. 그런 다음 단위 테스트는 재료가 신선하고 맛있는 지 확인하는 것과 같습니다. 통합 테스트는 식사가 맛있는 지 확인하는 것과 같습니다.

궁극적으로 식사가 맛 있거나 시스템이 작동하는지 확인하는 것이 가장 중요한 목표입니다. 그러나 당신의 재료, 즉 단위, 작동한다면, 당신은 더 싼 방법을 찾을 것입니다.

실제로, 장치 / 방법이 작동한다고 보장 할 수 있다면 작동하는 시스템이있을 가능성이 높습니다. 나는 “확실한”과는 반대로 “보다 가능성이 높다”고 강조합니다. 요리 한 음식을 맛보고 최종 제품이 좋다고 말하는 사람이 필요 하듯이 통합 테스트가 여전히 필요합니다. 신선한 재료로 쉽게 갈 수 있습니다.


답변

장치를 완전히 분리하여 테스트하면 가능한 모든 데이터 및 상황을 제출할 수 있습니다. 나머지와 분리되어 있으므로 테스트 할 장치에 직접적인 영향을 미치지 않는 변형을 무시할 수 있습니다. 결과적으로 테스트의 복잡성이 크게 줄어 듭니다.

다양한 수준의 종속성을 통합하여 테스트하면 단위 테스트에서 테스트되지 않은 특정 시나리오를 테스트 할 수 있습니다.

둘 다 중요합니다. 단위 테스트 만하면 구성 요소를 통합 할 때 발생하는보다 복잡한 미묘한 오류가 발생합니다. 통합 테스트 만하면 시스템의 개별 부품이 테스트되지 않았다는 확신없이 시스템을 테스트 할 수 있습니다. 통합 테스트를 수행하는 것만으로도 더 나은 완전한 테스트를 달성 할 수 있다고 생각하는 것은 엔트리 조합의 수를 추가할수록 더 많은 구성 요소가 매우 빠르게 증가하고 (계수 적) 충분한 커버리지로 테스트를 작성하는 것은 매우 빠르게 불가능하므로 거의 불가능합니다.

간단히 말해, 나는 거의 모든 프로젝트에서 일반적으로 사용하는 세 가지 레벨의 “단위 테스트”를 사용합니다.

  • 단일 구성 요소의 지옥을 테스트하기 위해 모의 또는 스터 빙 종속성으로 격리 된 단위 테스트. 이상적으로는 완전한 커버리지를 시도 할 것입니다.
  • 보다 미묘한 오류를 테스트하기위한 통합 테스트. 제한 사례와 일반적인 조건을 보여주는 신중하게 제작 된 현장 점검. 완전한 적용 범위가 불가능한 경우가 많으며, 시스템 장애를 일으키는 원인에 중점을 둡니다.
  • 시스템에 다양한 실제 데이터를 주입하고, 가능한 경우 데이터를 계측하고, 출력이 사양 및 비즈니스 규칙을 준수하는지 확인하기위한 사양 테스트.

의존성 주입은 시스템에 복잡성을 추가하지 않고도 단위 테스트를 위해 구성 요소를 매우 쉽게 분리 할 수 ​​있으므로이를 달성하는 매우 효율적인 방법 중 하나입니다. 비즈니스 시나리오는 주입 메커니즘 사용을 보증하지는 않지만 테스트 시나리오는 거의 사용됩니다. 이것은 나를 위해 필수 불가결 한 것으로 충분합니다. 이들을 사용하여 부분 통합 테스트를 통해 독립적으로 다른 레벨의 추상화를 테스트 할 수 있습니다.


답변

이것의 반대편은 무엇입니까? 단위 테스트가 종속성을 테스트하지 않는 것이 정말로 중요합니까? 그렇다면 왜 그렇습니까?

단위. 단수를 의미합니다.

두 가지를 테스트한다는 것은 두 가지 모든 기능적 종속성 이 있음을 의미합니다 .

세 번째 항목을 추가하면 테스트의 기능적 종속성이 선형 적으로 증가합니다. 사물 사이의 상호 연결은 사물 수보다 더 빠르게 커집니다.

테스트중인 n 개의 항목 중에서 n (n-1) / 2의 잠재적 종속성이 있습니다.

그게 큰 이유입니다.

단순성은 가치가 있습니다.


답변

재귀를 처음 배운 방법을 기억하십니까? 내 교수는 “x를 수행하는 방법이 있다고 가정합니다”라고 말합니다 (예 : 피보나치 문제를 x로 해결). “x를 해결하려면 x-1과 x-2에 대해 해당 메소드를 호출해야합니다.” 같은 점에서, 의존성을 제거하는 것은 그들이 존재하는 척하고 현재 유닛이해야 할 일을 수행하는지 테스트 할 수있게합니다. 물론 의존성을 엄격하게 테스트한다고 가정합니다.

이것은 본질적으로 직장에서의 SRP입니다. 심지어 검사에 대한 단일 책임에 집중하면해야 할 정신적 저글링의 양이 줄어 듭니다.