모의 객체를 사용할 때 단위 테스트와 관련된 종속성 문제를 어떻게 감지합니까?


98

클래스 X가 있고 동작 X1을 확인하는 몇 가지 단위 테스트를 작성합니다. X를 종속성으로 사용하는 클래스 A도 있습니다.

A에 대한 단위 테스트를 작성할 때 X를 조롱합니다. 즉, 단위 테스트 A 동안 X의 모의 동작을 X1로 설정 (가정)합니다. 시간이 지남에 따라 사람들이 시스템을 사용하고 변화가 필요하며 X가 진화합니다. X를 수정하여 X2 동작을 표시합니다. 분명히, X에 대한 단위 테스트는 실패 할 것이고 당신은 그것들을 적응시켜야합니다.

그러나 A는 어떻습니까? X 동작이 수정 될 때 (X 조롱으로 인해) A에 대한 단위 테스트가 실패하지 않습니다. "실제"(수정 된) X로 실행할 때 A의 결과가 다르다는 것을 감지하는 방법은 무엇입니까?

나는 "그것이 단위 테스트의 목적이 아닙니다"라는 라인을 따라 대답을 기대하고 있습니다. 그러나 단위 테스트는 어떤 가치가 있습니까? 모든 테스트가 통과 될 때 주요 변경 사항을 도입하지 않았다는 것을 실제로 알려주는 것입니까? 그리고 어떤 클래스의 행동이 (의지 적이든 또는 의지 적이든) 변할 때, 모든 결과를 어떻게 (바람직하게는 자동화 된 방식으로) 감지 할 수 있습니까? 통합 테스트에 더 집중해서는 안됩니까?



36
제안 모든 해답뿐만 아니라, 나는 다음과 같은 문으로 문제를 가지고 말을해야 '정말합니까 에만 모든 테스트를 통과 할 때, 당신은 주요 변경을 도입하지 않은 것을 당신에게?' 리팩토링에 대한 두려움을 제거하는 것이 가치가 없다고 생각한다면, 유지 보수 할 수없는 코드를 작성하는 데
앞장서고

5
단위 테스트는 코드 단위가 예상대로 동작하는지 알려줍니다. 더 많거나 적습니다. Mocks 및 Test Doubles는 코드 단위 (단독)를 사용하여 예상과 일치하는지 확인할 수있는 인공 제어 환경을 제공합니다. 더 많거나 적습니다.
Robert Harvey

2
당신의 전제가 잘못되었다고 생각합니다. 언급 X1할 때 X인터페이스 를 구현 한다고 말하고 있습니다 X1. 다른 테스트에서 사용한 모의로 인터페이스 X1를 변경하면 X2더 이상 컴파일되지 않아야하므로 해당 테스트도 수정해야합니다. 수업 행동의 변화는 중요하지 않습니다. 실제로 클래스 A는 구현 세부 사항 (이 경우 변경 될 내용)에 의존해서는 안됩니다. 따라서 단위 테스트 A는 여전히 정확 A하며 인터페이스의 이상적인 구현이 주어진 것으로 작동합니다.
Bakuriu

5
나는 당신에 대해 모른다. 그러나 테스트없이 코드베이스에서 작업해야 할 때, 나는 무서워서 무언가를 깨뜨릴 것이다. 그리고 왜? 의도하지 않았을 때 무언가가 자주 발생하기 때문에 발생합니다. 테스터의 마음을 축복하면 모든 것을 테스트 할 수 없습니다. 아니면 가까이. 그러나 단위 테스트는 지루한 작업 후에 지루한 작업을 통해 행복하게 제거됩니다.
corsiKa

답변:


125

A에 대한 단위 테스트를 작성할 때 X를 조롱

당신 은요? 절대적으로 필요한 경우가 아니면 안됩니다. 나는 만약에 :

  1. X 느리거나
  2. X 부작용이있다

이 중 어느 것도 해당되지 않는다면, 나의 단위 테스트도 테스트 A할 것 X입니다. 다른 작업을 수행하는 것은 비논리적 인 극단적 인 테스트를 수행하는 것입니다.

코드의 다른 부분을 모의하여 코드의 일부를 가지고 있다면 동의 할 것입니다. 그러한 단위 테스트의 요점은 무엇입니까? 그러지 마 이러한 테스트는 훨씬 더 중요한 테스트를 구성 할 때 실제 종속성을 사용하게하십시오.

그리고 어떤 사람들이 당신이 이러한 테스트를 "단위 테스트"라고 부르는 것에 화를 내면 "자동 테스트"라고 부르고 좋은 자동 테스트를 작성하십시오.


94
@Laiv, 아니요, 단위 테스트는 다른 테스트는 달리 단위로 작동합니다 (즉, 독립적으로 실행) . 노드와 그래프는 하이킹을 할 수 있습니다. 단시간에 고립 된 부작용이없는 엔드-투-엔드 테스트를 실행할 수 있다면 이는 단위 테스트입니다. 그 정의가 마음에 들지 않으면 자동 테스트라고 부르고 바보 같은 의미에 맞도록 쓰레기 테스트 작성을 중단하십시오.
David Arno

9
@DavidArno 슬프게도 isolated에 대한 매우 광범위한 정의가 있습니다. 일부는 "단위"가 중간 계층과 데이터베이스를 포함하기를 원합니다. 그들은 자신이 좋아하는 것을 믿을 수 있지만 모든 규모의 개발에서 바퀴는 빌드 매니저가 그것을 버릴 정도로 상당히 짧은 순서로 나올 것입니다. 일반적으로 어셈블리와 격리되거나 이와 동등한 경우 괜찮습니다. NB 인터페이스에 코딩하면 나중에 조롱과 DI를 추가하는 것이 훨씬 쉽습니다.
Robbie Dee

13
당신은 질문에 대답하기보다는 다른 종류의 시험을 옹호합니다. 어느 것이 타당한 지 알 수 있지만, 이것은 꽤 확실한 방법입니다.
Phil Frost

17
"PhilFrost,"나 자신을 인용하기 위해, " 일부 사람들이이 테스트를"단위 테스트 "라고 부르는 것에 화를 내면"자동 테스트 "라고 부르고 좋은 자동화 된 테스트를 작성하십시오 . "어리석은 테스트가 아닌 유용한 테스트를 작성하십시오 . 그것은 단어의 임의의 정의를 단순히 충족시킵니다. 또는 "unit test"에 대한 정의가 잘못되었거나 모의가 잘못되어 모의를 과도하게 사용하고 있음을 인정하십시오. 어느 쪽이든, 당신은 더 나은 테스트로 끝날 것입니다.
David Arno

30
나는 이것에 @DavidArno와 함께 있습니다. 내 테스트 전략은 Ian Cooper ( vimeo.com/68375232)의 강연을 본 후에 바뀌 었 습니다 . 한 문장으로 정리하려면 : 클래스를 테스트하지 마십시오 . 행동 테스트 . 테스트에는 원하는 동작을 구현하는 데 사용되는 내부 클래스 / 메소드에 대한 지식이 없어야합니다. API / 라이브러리의 공개 영역 만 알고 테스트해야합니다. 테스트에 너무 많은 지식이 있다면 구현 세부 사항을 테스트하고 테스트가 취하기 쉽고 구현과 결합되어 실제로 목 주위에 고정됩니다.
Richiban

79

둘 다 필요합니다. 각 장치의 동작을 확인하기위한 장치 테스트 및 올바르게 연결되어 있는지 확인하기위한 몇 가지 통합 테스트. 통합 테스트에만 의존하는 문제는 모든 장치 간의 상호 작용으로 인한 조합 폭발입니다.

모든 경로를 완전히 덮기 위해 10 단위 테스트가 필요한 클래스 A가 있다고 가정 해 봅시다. 그런 다음 코드 B가 통과 할 수있는 모든 경로를 다루기 위해 10 가지 단위 테스트가 필요한 또 다른 클래스 B가 있습니다. 응용 프로그램에서 A의 출력을 B로 공급해야한다고 가정 해 봅시다. 이제 코드는 A의 입력에서 B의 출력까지 100 가지 경로를 취할 수 있습니다.

단위 테스트를 사용하면 모든 경우를 완전히 처리하기 위해 20 개의 단위 테스트 + 1 통합 테스트 만 있으면됩니다.

통합 테스트를 사용하면 모든 코드 경로를 다루기 위해 100 개의 테스트가 필요합니다.

통합 테스트에만 의존하는 단점에 대한 아주 좋은 비디오가 있습니다 JB Rainsberger 통합 테스트는 사기 HD입니다


1
통합 테스트의 효과에 대한 물음표가 더 많은 계층을 포함하는 단위 테스트와 나란히 일치하는 것은 아닙니다.
Robbie Dee

16
맞습니다. 그러나 20 개 단위 테스트에서 조롱이 필요한 곳은 없습니다. A에 대한 10 개의 테스트와 B에 대한 10 개의 테스트가 모두 있고 A의 25 %를 보너스로 다시 테스트하는 경우 이는 "좋음"과 좋은 것 사이에있는 것 같습니다. Bs 테스트에서 A를 조롱하는 것은 적극적으로 어리석은 것처럼 보입니다 (A가 문제가되는 이유가없는 한 (예 : 데이터베이스이거나 다른 것들의 긴 웹을 가져 오는 경우))
Richard Tingle

9
전체 범위를 원한다면 단일 통합 테스트로 충분하다는 생각에 동의하지 않습니다. B의 A 출력에 대한 반응은 출력에 따라 달라집니다. A에서 매개 변수를 변경하면 출력이 변경되면 B가 올바르게 처리하지 못할 수 있습니다.
Matthieu M.

3
@ Eternal21 : 내 요점은 때때로 문제가 개별 행동이 아니라 예기치 않은 상호 작용에 있다는 것입니다. 즉, 일부 시나리오에서 A와 B 사이 의 접착제 가 예기치 않게 작동하는 경우 입니다. 따라서 A와 B는 모두 사양에 따라 작동하고 행복한 경우는 효과가 있지만 일부 입력에는 접착제 코드에 버그가 있습니다.
Matthieu M.

1
@MatthieuM. 나는 이것이 단위 테스트의 범위를 벗어났다고 주장한다. 글루 코드를 통해 A와 B 간의 상호 작용은 통합 테스트 인 반면 글루 코드는 자체적으로 테스트 할 수 있습니다. 특정 에지 사례 또는 버그가 발견되면 글루 코드 단위 테스트에 추가되고 궁극적으로 통합 테스트에서 확인할 수 있습니다.
Andrew T Finnell

72

A에 대한 단위 테스트를 작성할 때 X를 조롱합니다. 즉, 단위 테스트 A 동안 X의 모의 동작을 X1로 설정 (가정)합니다. 시간이 지남에 따라 사람들이 시스템을 사용하고 변화가 필요하며 X가 진화합니다. X를 수정하여 X2 동작을 표시합니다. 분명히, X에 대한 단위 테스트는 실패 할 것이고 당신은 그것들을 적응시켜야합니다.

우와, 잠깐만 X 실패에 대한 테스트의 의미는 그렇게 광택을 내기에는 너무 중요합니다.

X의 구현을 X1에서 X2로 변경하면 X에 대한 단위 테스트가 중단되어 계약 X를 이전 버전과 호환되지 않게 변경했음을 나타냅니다.

X2는 Liskov의 의미 에서 X가 아니므로 이해 관계자의 요구를 충족시키는 다른 방법 (X2로 구현되는 새로운 사양 Y를 도입하는 것과 같은)에 대해 생각 해야합니다 .

더 깊은 통찰력을 얻으려면 Pieter Hinjens : 소프트웨어 버전의 끝 또는 Rich Hickey Simple Made Easy를 참조하십시오 .

A의 관점에서 볼 때 공동 작업자가 계약 X를 존중한다는 전제 조건 이 있습니다. 그리고 A에 대한 고립 된 테스트를 통해 A가 X 계약을 위반하는 공동 작업자를 인정한다는 어떠한 보증도하지 않습니다.

통합 테스트 검토 는 사기입니다 . 높은 수준에서는 X2가 계약 X를 올바르게 구현하는지 확인하기 위해 필요한만큼의 고립 된 테스트를 수행해야하며 A가 X의 흥미로운 응답을 제공하여 A가 옳은 일을하는지 확인하기 위해 필요한만큼의 고립 된 테스트를 수행해야합니다. X2와 A가 X의 의미에 동의하는지 확인하기위한 더 적은 수의 통합 테스트.

때때로이 구별은 독방 테스트 대 sociable테스트 로 표현됩니다 . Jay Fields가 효과적으로 단위 테스트 작업을 참조하십시오 .

통합 테스트에 더 집중해서는 안됩니까?

다시 한번 말하지만 통합 테스트는 사기입니다. Rainsberger는 통합 된 (주문 철자) 테스트에 의존하는 프로젝트에 공통적 인 긍정적 인 피드백 루프를 자세히 설명합니다. 요약하면, 디자인에 압력을 가하는 격리 / 독립 테스트가 없으면 품질이 저하되어 더 많은 실수와 더 통합 된 테스트로 이어집니다 ....

또한 (일부) 통합 테스트가 필요합니다. 여러 모듈에 의해 도입 된 복잡성 외에도 이러한 테스트를 실행하면 격리 된 테스트보다 더 많은 드래그가 발생합니다. 작업이 진행 중일 때 매우 빠른 검사를 반복하는 것이 더 효율적이며, "완료"되었다고 생각 될 때 추가 검사를 저장합니다.


8
이것이 정답입니다. 이 질문은 클래스의 동작이 호환되지 않는 방식으로 수정되었지만 여전히 겉으로는 동일하게 보이는 상황을 설명합니다. 여기서 문제는 단위 테스트가 아니라 응용 프로그램 설계에 있습니다. 이 상황이 테스트에서 포착되는 방식은 두 클래스 사이의 통합 테스트를 사용하는 것입니다.
Nick Coad

1
"디자인에 압력을 가하는 격리 / 독립 테스트가 없으면 품질이 저하됩니다." 이것이 중요한 포인트라고 생각합니다. 동작 검사와 함께 단위 테스트는 부작용이있어보다 모듈 식으로 설계 할 수 있습니다.
MickaëlG

나는 이것이 사실이라고 생각하지만, 외부 의존성이 계약 X에 호환되지 않는 변경을 도입하면 어떻게 도움이됩니까? 아마도 라이브러리의 I / O 수행 클래스는 호환성을 깨뜨리고 CI의 단위 테스트가 무거운 I / O에 의존하지 않기 때문에 X를 조롱하고 있습니다. OP 가이 테스트를 요구하고 있다고 생각하며 이것이 어떻게 질문에 대답하는지 이해하지 못합니다. 이것을 테스트하는 방법?
gerrit

15

질문의 핵심 전제에 결함이 있다고 말하면서 시작하겠습니다.

구현을 테스트하거나 조롱하지 않고 인터페이스를 테스트하고 조롱 합니다.

인터페이스 X1을 구현하는 실제 클래스 X가 있다면 X1과 호환되는 모의 XM을 작성할 수 있습니다. 그런 다음 클래스 A는 클래스 X 또는 모의 XM 일 수있는 X1을 구현하는 것을 사용해야합니다.

이제 X를 변경하여 새로운 인터페이스 X2를 구현한다고 가정하겠습니다. 음, 분명히 내 코드는 더 이상 컴파일되지 않습니다. A는 X1을 구현하고 더 이상 존재하지 않는 것을 요구합니다. 문제가 확인되었으며 해결할 수 있습니다.

X1을 교체하는 대신 수정하기 만하면됩니다. 이제 클래스 A가 모두 설정되었습니다. 그러나 모의 XM은 더 이상 인터페이스 X1을 구현하지 않습니다. 문제가 확인되었으며 해결할 수 있습니다.


단위 테스트 및 조롱의 전체 기초는 인터페이스를 사용하는 코드를 작성하는 것입니다. 인터페이스 소비자는 코드 구현 방식 에 신경 쓰지 않고 동일한 계약을 준수해야합니다 (입력 / 출력).

이 방법은 부작용이있을 때 세분화되지만 "단위 테스트 또는 조롱 할 수 없음"으로 안전하게 제외 될 수 있다고 생각합니다.


11
이 답변은 유지할 필요가없는 많은 가정을 만듭니다. 먼저, 대략 우리가 C # 또는 Java에 있다고 가정합니다 (또는 더 정확하게 말하면 컴파일 된 언어에 있고 언어에 인터페이스가 있으며 X가 인터페이스를 구현한다고 가정 할 수 있습니다). 둘째, X의 행동 또는 "계약"에 대한 변경 은 X가 구현 하는 인터페이스 (컴파일러에 의해 이해되는)에 대한 변경이 필요하다고 가정합니다 . 비록 우리 자바 나 C #을 사용 하더라도 이것은 사실 이 아닙니다 . 서명을 변경하지 않고 메소드 구현을 변경할 수 있습니다.
Mark Amery

6
@MarkAmery "인터페이스"용어가 C # 또는 Java에 더 구체적이라는 것은 사실이지만, 요점은 정의 된 "계약"동작의 동작을 가정하는 것으로 생각합니다 (그러면 코드화되지 않은 경우 자동으로 감지하는 것은 불가능합니다). 계약을 변경하지 않고 구현을 변경할 수 있다는 것도 완전히 정확합니다. 그러나 인터페이스 (또는 계약)를 변경하지 않고 구현을 변경해도 소비자에게는 영향을 미치지 않습니다. A의 동작이 인터페이스 (또는 계약)가 구현되는 방법에 따라 달라지면 단위 ​​테스트를 수행 할 수 없습니다.
Vlad274

1
"계약을 변경하지 않고 구현을 변경할 수 있다는 것도 완전히 정확합니다." -사실이지만 이것이 제가 의도 한 것은 아닙니다. 오히려 계약 (문서에 명시된 객체가 무엇을 해야하는지 프로그래머가 이해함)과 인터페이스 (컴파일러가 이해하는 메소드 서명 목록 )와 계약 이 가능 하다는 것을 구별 하고 있습니다. 인터페이스를 변경하지 않고 변경하십시오. 동일한 시그니처를 가진 모든 기능은 유형 시스템의 관점에서 서로 교환 가능하지만 실제로는 그렇지 않습니다!
Mark Amery

4
@MarkAmery : Vlad가 사용하는 것과 같은 의미로 "인터페이스"라는 단어를 사용하고 있다고 생각하지 않습니다. 대답을 읽는 방식은 좁은 C # / Java 의미 (예 : 메소드 서명 세트)의 인터페이스에 대한 것이 아니라 "응용 프로그램 프로그래밍 인터페이스"또는 " 사용자 인터페이스 ". [...]
Ilmari Karonen

6
@IlmariKaronen Vlad가 좁은 C # / Java 의미가 아닌 "계약"을 의미하기 위해 "인터페이스"를 사용하는 경우 "이제 X를 새로운 인터페이스 X2를 구현하도록 변경한다고 가정하겠습니다. 음, 분명히 내 코드는 더 이상 컴파일되지 않습니다. " 메소드 서명을 변경하지 않고 계약을 변경할 수 있기 때문에 단지 거짓입니다. 그러나 솔직히 말해서, 여기서 문제는 Vlad가 일관된 의미를 사용하지 않지만 그 개념을 혼란스럽게 만들고 있다는 것입니다. 이것은 계약 X1을 변경하면 반드시 거짓임을 알지 않고 컴파일 오류를 일으킬 것이라고 주장하는 경로를 이끌어 냅니다 .
Mark Amery

9

차례대로 질문하기 :

그러면 단위 테스트의 가치는 무엇입니까

작성 및 실행 비용이 저렴하며 조기 피드백을받습니다. X를 깨면, 좋은 테스트를 받으면 즉시 더 많거나 적은 것을 알 수 있습니다. 모든 계층 (예 : 데이터베이스에서도)을 단위로 테스트하지 않은 경우 통합 테스트 작성을 고려하지 마십시오.

실제로 모든 테스트가 통과 될 때 주요 변경 사항을 도입하지 않았다는 사실 만 알려줍니다

시험에 합격하면 실제로 거의 말할 수 없습니다. 충분한 테스트를 작성하지 않았을 수 있습니다. 충분한 시나리오를 테스트하지 않았을 수 있습니다. 코드 범위가 여기에 도움이 될 수 있지만 은총 알이 아닙니다. 항상 통과 하는 테스트가있을 수 있습니다 . 따라서 빨강은 자주 간과되는 빨강, 초록, 리팩터링의 첫 단계입니다.

그리고 어떤 수업의 행동이 (의지 적이든 또는 의지 적이든) 변할 때, 모든 결과를 어떻게 (바람직하게는 자동화 된 방식으로) 감지 할 수 있습니까?

더 많은 테스트-도구가 점점 나아지고 있지만. 그러나 인터페이스에서 클래스 동작을 정의해야합니다 (아래 참조). NB는 항상 테스트 피라미드 위에 수동 테스트를위한 장소가있을 것입니다.

통합 테스트에 더 집중해서는 안됩니까?

더 많은 통합 테스트도 답이 아니며 작성, 실행 및 유지 관리 비용이 많이 듭니다. 빌드 설정에 따라 빌드 관리자는 어쨌든 개발자가 기억하는 개발자에게 의존하게 만드는 것을 제외시킬 수 있습니다 (좋은 일은 아닙니다!).

개발자가 우수한 단위 테스트를 수행 한 경우 5 분 내에 발견 된 손상된 통합 테스트를 수정하는 데 몇 시간을 소비하는 것을 보았습니다. 실패하면 소프트웨어를 실행 해보십시오. 최종 사용자가 신경 쓸 것입니다. 사용자가 전체 제품군을 실행할 때 전체 카드 하우스가 쓰러지면 통과하는 백만 단위 테스트가 없습니다.

클래스 A가 동일한 방식으로 클래스 X를 사용하도록하려면 concretion이 아닌 인터페이스를 사용해야합니다. 그러면 컴파일 타임에 주요 변경 사항이 발생할 가능성이 높습니다.


9

맞습니다.

장치 테스트는 장치의 격리 된 기능을 테스트하기 위해 수행됩니다. 장치가 의도 한대로 작동하고 어리석은 오류가 없는지 한 눈에 확인합니다.

전체 응용 프로그램이 작동하는지 테스트하기위한 단위 테스트는 없습니다.

많은 사람들이 잊어 버린 것은 단위 테스트가 코드를 확인하는 가장 빠르고 더러운 수단이라는 것입니다. 작은 루틴이 작동하는 것을 알고 나면 통합 테스트도 실행해야합니다. 단위 테스트 자체는 테스트를 수행하지 않는 것보다 조금 더 좋습니다.

우리가 단위 테스트를하는 이유는 값이 싸야하기 때문입니다. 작성 및 실행 및 유지 보수가 빠릅니다. 최소 통합 테스트로 전환하기 시작하면 어려움에 처하게됩니다. 전체 통합 테스트를 수행하고 단위 테스트를 무시할 수도 있습니다.

이제 어떤 사람들은 단위가 클래스의 함수가 아니라 전체 클래스 자체 (자체 포함)라고 생각합니다. 그러나이 모든 것은 장치의 크기를 늘리므로 통합 테스트가 덜 필요하지만 여전히 필요합니다. 완전한 통합 테스트 스위트 없이는 프로그램이 수행해야하는 작업을 검증하는 것은 여전히 ​​불가능합니다.

그런 다음 고객이 사용하는 조건에서 작동하는지 확인하려면 라이브 (또는 세미 라이브) 시스템에서 전체 통합 테스트를 계속 실행해야합니다.


2

단위 테스트는 정확성을 입증하지 못합니다. 이것은 모든 테스트에 해당됩니다. 일반적으로 단위 테스트는 계약 기반 설계 (계약에 의한 설계는 다른 말로 표현할 수있는 방법) 및 가능하면 정기적으로 정확성을 검증해야하는 경우 자동 정확성 교정과 결합됩니다.

클래스 불변량, 전제 조건 및 사후 조건으로 구성된 실제 계약이있는 경우 하위 레벨 구성 요소의 계약을 기반으로 상위 레벨 구성 요소의 정확성을 기반으로하여 계층 적으로 정확성을 입증 할 수 있습니다. 이것이 계약에 의한 설계의 기본 개념입니다.


단위 테스트는 정확성을 입증하지 못합니다 . 잘 모르겠습니다. 단위 테스트에서 자체 결과를 확인하십시오. 또는 여러 계층을 포함 할 수 있으므로 동작을 올바르게 입증 할 수 없다는 의미입니까?
Robbie Dee

7
내 생각 @RobbieDee, 그는 당신이 테스트 할 때 의미 fac(5) == 120, 당신이 없는 것을 증명 fac()실제로 인수의 계승을 반환 않습니다. 에 fac()전달하면 5의 계승 을 반환하는 것으로 입증되었습니다 5. 팀북투에서 개기 일주일 만에 첫 월요일에 대신 fac()돌아올 수 있기 때문에 확실하지 않습니다 42. 여기서 문제는 개별 테스트 입력을 확인하여 준수를 입증 할 수 없다는 것입니다. 가능한 모든 입력 을 확인 해야 합니다. 또한 시스템 시계를 읽는 등 잊어 버린 적이 없다는 것을 증명하십시오.
cmaster

1
@RobbieDee 테스트 (단위 테스트 포함)는 기계 검사 증명이라는 실제 목표를 위해 가장 적합하지 않은 대체품입니다. 테스트중인 유닛의 전체 상태 공간 (구성 요소 또는 모의 상태 공간 포함)을 고려하십시오. 매우 제한된 상태 공간이 없으면 테스트는 해당 상태 공간을 커버 할 수 없습니다. 완전한 적용 범위는 증명이 될 수 있지만 작은 상태 공간 (예 : 단일 가변 바이트 또는 16 비트 정수를 포함하는 단일 객체 테스트)에서만 사용할 수 있습니다. 자동화 된 증명은 훨씬 더 가치가 있습니다.
Frank Hileman

1
@cmaster 테스트와 증명의 차이점을 잘 요약했습니다. 감사!
Frank Hileman

2

매우 조롱 된 테스트는 거의 유용하지 않습니다. 대부분의 경우, 나는 원래 클래스가 이미 가지고있는 행동을 다시 구현하여 조롱의 목적을 완전히 상실합니다.

나에게 더 나은 전략은 우려를 잘 구분하는 것입니다 (예 : 파트 B에서 Z까지 가져 오지 않고 앱의 파트 A를 테스트 할 수 있음). 이러한 훌륭한 아키텍처는 실제로 좋은 테스트를 작성하는 데 도움이됩니다.

또한 롤백 할 수있는 한 부작용을 기꺼이 받아들입니다. 예를 들어 내 방법이 db의 데이터를 수정하는 경우하자. db를 이전 상태로 롤백 할 수 있다면, 어떤 피해가 있습니까? 또한 테스트에서 데이터가 예상대로 보이는지 확인할 수있는 이점이 있습니다. 메모리 내 DB 또는 특정 DB 테스트 버전 (예 : RavenDB 메모리 내 테스트 버전)이 여기에 실제로 도움이됩니다.

마지막으로, 서비스 경계에 대해 조롱하고 싶습니다. 예를 들어 http를 서비스 b에 호출하지는 않지만 가로 채서 적절한 방법을 소개하겠습니다.


1

두 캠프의 사람들이 수업 테스트와 행동 테스트가 직교하지 않다는 것을 이해하기를 바랍니다.

클래스 테스트와 단위 테스트는 서로 바꿔 사용할 수 있으므로 사용하지 않아야합니다. 일부 단위 테스트는 클래스에서 구현 되기만합니다. 그게 다야 단위 테스트는 수업이없는 언어로 수십 년 동안 진행되었습니다.

동작 테스트에 대해서는 GWT 구문을 사용하여 클래스 테스트 내에서 완벽하게 수행 할 수 있습니다.

또한 자동화 된 테스트가 클래스 또는 행동 라인을 따라 진행되는지 여부는 우선 순위에 따라 다릅니다. 일부는 신속하게 프로토 타입을 만들어 무언가를 꺼내야하는 반면, 다른 이들은 하우스 스타일로 인해 적용 범위 제한이 있습니다. 많은 이유. 둘 다 완벽하게 유효한 접근 방식입니다. 당신은 당신의 돈을 지불, 당신은 선택을합니다.

따라서 코드가 중단되면 어떻게해야합니까? 인터페이스로 코딩 된 경우 테스트와 함께 concretion 만 변경하면됩니다.

그러나 새로운 동작을 도입해도 시스템이 전혀 손상 될 필요는 없습니다. Linux 등은 더 이상 사용되지 않는 기능으로 가득합니다. 또한 모든 호출 코드를 변경하지 않고도 생성자 (및 메서드)와 같은 항목을 행복하게 오버로드 할 수 있습니다.

수업 테스트에서이기는 곳은 아직 시간 제약, 복잡성 또는 기타 이유로 인해 아직 연결되지 않은 클래스를 변경해야하는 곳입니다. 종합적인 시험이 있으면 수업을 시작하는 것이 훨씬 쉽습니다.


당신이 concretion 이있는 곳에서 구현 을 작성했을 것 입니다. 이것은 다른 언어의 칼크입니까 (프랑스어를 추측 할 것입니다) 또는 concretion구현 사이에 중요한 차이점이 있습니까?
피터 테일러

0

X에 대한 인터페이스가 변경되지 않으면 A와 관련된 항목이 변경되지 않았으므로 A에 대한 단위 테스트를 변경할 필요가 없습니다. 실제로 X와 A의 단위 테스트를 작성했지만 A의 단위 테스트라고 불렀습니다.

A에 대한 단위 테스트를 작성할 때 X를 조롱합니다. 즉, 단위 테스트 A 동안 X의 모의 동작을 X1로 설정 (가정)합니다.

이상적으로 X의 모의는 X 에서 기대 하는 동작뿐만 아니라 X의 모든 가능한 동작을 시뮬레이션 해야합니다. 따라서 실제로 X에서 구현하는 것이 무엇이든 A는 이미 X를 처리 할 수 ​​있어야합니다. 따라서 인터페이스 자체를 변경하는 것 외에 X 로의 변경은 A의 단위 테스트에 영향을 미치지 않습니다.

예를 들어, A가 정렬 알고리즘이고 A가 정렬 할 데이터를 제공한다고 가정하십시오. X의 모의는 null 반환 값, 빈 데이터 목록, 단일 요소, ​​이미 정렬되지 않은 여러 요소, 정렬되지 않은 여러 요소, 뒤로 정렬 된 여러 요소, 동일한 요소가 반복 된 목록, null 값이 섞인 목록을 엄청나게 제공해야합니다. 많은 수의 요소가 있으며 예외도 발생해야합니다.

아마 X는 월요일에 정렬 된 데이터를, 화요일에는 빈 목록을 반환했을 것입니다. 그러나 이제 X가 월요일에 분류되지 않은 데이터를 반환하고 화요일에 예외를 throw하면 A는 상관하지 않습니다. 이러한 시나리오는 이미 A의 단위 테스트에서 다루었습니다.


X가 반환 된 배열의 인덱스 이름을 foobar에서 foobarRandomNumber로 바꾼 경우 어떻게 계산할 수 있습니까? 내 요점을 얻는다면, 이것은 기본적으로 내 문제이며, 반환 된 열의 이름을 secondName에서 성을 고전적인 작업으로 바꾸었지만 테스트는 모의 한 이후 알 수 없습니다. 이 질문에 많은 사람들이 실제로 주석 전에, 그런 일을 해본 적이처럼 그냥 같은 이상한 느낌이
FantomX1

컴파일러가이 변경 사항을 감지하고 컴파일러 오류가 발생했을 것입니다. Javascript와 같은 것을 사용하는 경우 Typescript로 전환하거나 Babel과 같은 컴파일러를 사용 하여이 것을 감지하는 것이 좋습니다.
Moby Disk

PHP, Java 또는 Javascript에서 배열을 사용하는 경우 배열 색인을 변경하거나 제거하면 해당 언어가 아닌 컴파일러에서 알려줍니다. 색인은 36 번째에 중첩 될 수 있습니다. 배열의 중첩 된 수준이므로 컴파일러가 이것에 대한 해결책이 아니라고 생각합니다.
FantomX1

-2

다른 테스트를 봐야합니다.

단위 테스트 자체는 X 만 테스트합니다. X의 동작이 변경되는 것을 방지하지만 전체 시스템을 보호하지는 않습니다. 행동 변화를 일으키지 않고 수업을 리팩토링 할 수 있습니다. 그리고 당신이 X를 깨면, 당신은 그것을 깨뜨 렸습니다 ...

A 는 실제로 단위 테스트를 위해 X를 조롱해야하며 Mock을 사용한 테스트는 변경 한 후에도 계속 통과해야합니다.

그러나 여러 수준의 테스트가 있습니다! 통합 테스트도 있습니다. 이 테스트는 클래스 간의 상호 작용을 확인하기위한 것입니다. 이 테스트는 모든 것에 모의를 사용하지 않기 때문에 일반적으로 더 높은 가격을 갖습니다. 예를 들어, 통합 테스트는 실제로 데이터베이스에 레코드를 쓸 수 있으며 단위 테스트에는 외부 종속성이 없어야합니다.

또한 X에 새로운 동작이 필요한 경우 원하는 결과를 제공하는 새로운 방법을 제공하는 것이 좋습니다

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.