유용한 단위 테스트가 무엇인지 결정


46

나는 phpunit의 문서를 살펴보고 다음 인용문을 가로 질러왔다.

언제든지 더 많은 테스트를 작성할 수 있습니다. 그러나 상상할 수있는 테스트의 일부만 실제로 유용하다는 것을 금방 알 수 있습니다. 원하는 것은 작동한다고 생각하더라도 실패하는 테스트 또는 실패한다고 생각하더라도 성공하는 테스트를 작성하는 것입니다. 그것을 생각하는 또 다른 방법은 비용 / 혜택 용어입니다. 정보를 갚을 테스트를 작성하려고합니다. -에리히 감마

궁금해졌습니다. 비용 / 혜택에 대한 인용문에 언급 된 것 외에 다른 단위 테스트보다 더 유용한 단위 테스트를 결정하는 방법은 무엇입니까? 단위 테스트를 생성하는 코드를 결정하는 방법은 무엇입니까? 나는 그 인용문 중 하나가 또한 말하기 때문에 그것을 묻습니다.

테스트에 관한 것이 아니라면 무엇입니까? 반쯤 걷어차 기 전에하려고하는 일을 알아내는 것입니다. 간결하고 모호하지 않으며 실행 가능한 형태로 동작의 작은 측면을 제시하는 사양을 작성합니다. 그렇게 간단합니다. 테스트를 작성한다는 의미입니까? 아니요. 코드에서 수행 할 작업의 사양을 작성한다는 의미입니다. 즉, 코드 동작을 미리 지정해야합니다. 그러나 아직 멀지 않은 시간입니다. 실제로, 코드를 작성하기 직전에 그 시점까지 정보를 손에 넣었을 때가 가장 좋습니다. 잘 수행 된 TDD와 마찬가지로 한 번에 하나의 작은 동작 측면 만 지정한 다음 구현하면 조금씩 증가합니다. 테스트 작성이 아니라 행동 지정에 관한 것임을 알게되면, 당신의 관점이 바뀝니다. 갑자기 각 프로덕션 클래스에 대한 테스트 클래스를 갖는 아이디어는 엄청나게 제한적입니다. 그리고 자신의 테스트 방법으로 (1-1 관계에서) 각 방법을 테스트한다는 생각은 재미있을 것입니다. -데이브 아 스텔

그 중요한 부분은

* 그리고 각 방법을 자체 테스트 방법 (1-1 관계)으로 테스트한다는 생각은 웃을 수 있습니다. *

따라서 각 방법에 대한 테스트 작성이 '웃을 수있는'경우 테스트 작성 대상을 언제 / 어떻게 선택합니까?


5
좋은 질문이지만 프로그래밍 언어와 독립적 인 질문 인 이유는 무엇입니까?

다음은 제가 작성해야하는 단위 테스트와 자동화 된 테스트를 제공하는 데 중요한 영역에 대한 지침을 제공하는 정말 유용한 기사입니다. - blog.stevensanderson.com/2009/11/04/... - blog.stevensanderson.com/2009/08/24/... - ayende.com/blog/4218/scenario-driven-tests

답변:


26

방법 당 몇 개의 테스트가 있습니까?

이론적으로 매우 비실용적 인 최대 값은 N-Path 복잡성입니다 (테스트를 통해 코드를 통해 다른 방법을 모두 적용한다고 가정). 최소값은 ONE!입니다. 퍼블릭 메서드 당 , 그는 구현 세부 사항을 테스트하지 않고 클래스의 외부 동작 만 반환합니다 (값 반환 및 다른 객체 호출).

당신은 인용 :

* 각 방법을 자체 테스트 방법 (1-1 관계로)으로 테스트한다는 생각은 웃을 수 있습니다. *

그리고 물어보십시오 :

따라서 각 방법에 대한 테스트 작성이 '웃을 수있는'경우 테스트 작성 대상을 언제 / 어떻게 선택합니까?

그러나 나는 당신이 저자를 오해했다고 생각합니다.

one test methodper 의 아이디어는 one method in the class to test저자가 "웃음"이라고 부르는 것입니다.

(적어도 나를 위해) 그것은 '더 적은'에 관한 것이 아니라 '더 많은'에 관한 것입니다.

내가 그를 이해 한 것처럼 다시 말해서

그리고 하나의 방법 (1-1 관계의 자체 테스트 방법) 만으로 각 방법을 테스트한다는 생각은 웃을 수 있습니다.

견적을 다시 인용하려면 :

테스트를 작성하지 않고 동작을 지정하는 것이 중요하다는 것을 인식하면 관점이 바뀝니다.


당신 TDD를 연습 할 때 당신 은 생각하지 않습니다 :

방법이 있는데 방법 에 대한 모든 것을 테스트 calculateX($a, $b);하는 테스트 testCalculcateX가 필요합니다 .

TDD가 말하는 것은 코드가 무엇을 좋아 하는지 생각하는 것입니다 .

두 값 중 큰 값을 계산해야 하지만 ( 첫 번째 테스트 사례! ) $ a가 0보다 작은 경우 오류가 발생하고 ( 두 번째 테스트 사례! ) $ b가 0보다 작은 경우 .... ( 세 번째 테스트 사례! ) 등등.


컨텍스트가없는 단일 메소드 만이 아니라 동작을 테스트하려고합니다.

그렇게하면 코드에 대한 문서 인 테스트 스위트를 얻을 수 있으며 REALY는 예상되는 작업, 아마도 이유를 설명합니다 :)


단위 테스트를 생성하는 코드를 결정하는 방법은 무엇입니까?

저장소 또는 프로덕션 근처에있는 모든 것은 테스트가 필요합니다. 나는 위의 진술을 시도했을 때 당신의 인용문의 저자가 그것에 동의하지 않을 것이라고 생각합니다.

테스트를하지 않은 경우, 특히 변경하지 않은 경우 코드를 변경하기가 더 어렵습니다 (비용이 많이 듭니다).

TDD는 모든 테스트를 보장하는 방법이지만 테스트를 작성하는 한 괜찮습니다. 보통 같은 날에 글을 쓰면 나중에하지 않을 것이므로 도움이됩니까? :)



의견에 대한 답변 :

적절한 방법은 다른 방법에 의존하거나 의존하기 때문에 특정 상황에서 테스트 할 수 없습니다

이러한 메소드가 호출 할 수있는 것은 세 가지입니다.

다른 클래스의 공개 메소드

우리는 다른 클래스를 조롱하여 거기에 상태를 정의했습니다. 우리는 상황을 통제하여 문제가되지 않도록합니다.

* 동일한 보호 또는 개인 방법 *

클래스의 공개 API에 포함되지 않은 것은 일반적으로 직접 테스트되지 않습니다.

당신은 테스트 동작하지 구현 원하는 클래스가 하나의 큰 공공 방법 또는 호출되는 많은 작은 보호 방법에있는 모든 그것의 작업을 수행하는 경우입니다 구현 . 테스트를 건드리지 않고 보호 된 방법을 변경할 수 있기를 원합니다. 코드 변경 동작이 변경되면 테스트가 중단되기 때문입니다! 당신이 무언가를 깨뜨릴 때 당신에게 알려주기 위해 테스트가 있습니다. :)

같은 클래스의 공개 메소드

그렇게 자주 발생하지 않습니까? 그리고 다음 예제 에서처럼 이것을 처리하는 몇 가지 방법이 있습니다.

$stuff = new Stuff();
$stuff->setBla(12);
$stuff->setFoo(14);
$stuff->execute(); 

세터가 존재하고 실행 메소드 서명의 일부가 아닌 것은 또 다른 주제입니다.)

여기서 우리가 테스트 할 수있는 것은 잘못된 값을 설정할 때 실행이 폭발하는지입니다. 즉 setBla당신이 문자열이 개별적으로 테스트 할 수 있습니다 통과 할 때 예외를 throw하지만 우리는 두 허용되는 값 (12 및 14) 그게 전부 하나 개의 테스트 케이스보다 (어떤 이유) 작업 TOGETHER을하지 않는 테스트를합니다.

"좋은"테스트 스위트를 원한다면 PHP에서 어쩌면 (!) @covers Stuff::execute주석을 추가 하여이 메소드에 대한 코드 적용 범위 만 생성하고 설정 된 다른 것만 별도로 테스트해야합니다 ( 당신은 그것을 원합니다).

요점은 다음과 같습니다. 어쩌면 주변 세계를 먼저 만들어야 할 수도 있지만 일반적으로 하나 또는 두 개의 실제 기능 (세터는 여기에 포함되지 않음)에만 적용되는 의미있는 테스트 사례를 작성할 수 있어야합니다. 나머지는 에테르로 조롱하거나 먼저 테스트 한 다음 신뢰할 수 있습니다 (참조 @depends)


* 참고 : 질문은 SO에서 마이그레이션되었으며 처음에는 PHP / PHPUnit에 관한 것이 었습니다. 샘플 코드와 참조가 PHP 세계에서 온 이유입니다 .phpunit은 다른 xUnit과 크게 다르지 않으므로 다른 언어에도 적용 할 수 있다고 생각합니다 테스트 프레임 워크.


매우 상세하고 유익한 정보 ... "컨텍스트가없는 단일 메소드 만이 아니라 동작을 테스트하고 싶다"고 말했지만, 다른 메소드에 의존하거나 의존하기 때문에 특정 컨텍스트 내에서 적절한 양의 메소드를 테스트 할 수 없습니다. 따라서 유용한 시험 조건은 부양 가족이 시험을받는 경우에만 상황에 맞습니까? 아니면 내가 무슨 뜻인지 잘못 해석하고 있습니까?
zcourts

@ robinsonc494 나는 아마 내가이 함께 갈거야 어디 조금 더 설명 한 예에서 편집 할 수 있습니다
edorian

편집 및 예를 들어 주셔서 감사합니다. "혼동"테스트에 대해 읽었음에도 불구하고 구현에 초점을 둔 테스트 사례를 본질적으로 (어쩌면?) 생각했습니다.
zcourts

@ robinsonc494 어쩌면 이런 식으로 생각할 수도 있습니다. 누군가가 펀치를 뚫 으면 경찰에 연락하거나 도망칩니다. 그 행동. 사람이하는 일입니다. 그가 뇌에서 적은 전기 요금으로 유발 된 홍합을 사용한다는 사실은 실행입니다. 누군가의 반응을 테스트하려면 그를 펀치하고 그가 예상대로 행동하는지 확인하십시오. 그를 뇌 스캐너에 넣지 않고 충동이 홍합으로 보내지는지 확인하십시오. 일부는 거의 수업에 간다;)
edorian

3
테스트 케이스 작성 방법을 클릭하는 데 실제로 도움이 된 TDD의 가장 좋은 예는 Bob Martin 아저씨의 볼링 게임 Kata였습니다. slideshare.net/lalitkale/bowling-game-kata-by-robert-c-martin
에이미 Anuszewski

2

테스트와 단위 테스트는 동일하지 않습니다. 단위 테스팅은 전체적으로 테스팅의 매우 중요하고 흥미로운 부분 집합입니다. 나는 Unit Testing의 초점이 위의 인용과 다소 모순되는 방식으로 이러한 종류의 테스트에 대해 생각하게 만든다고 주장합니다.

첫째, TDD 또는 DTH를 따르는 경우 (예 : 밀접한 조화로 개발 및 테스트) 설계를 올바르게 작성하는 데 중점을두고 작성하는 테스트를 사용합니다. 코너 케이스에 대해 생각하고 그에 따라 테스트를 작성함으로써 우리는 처음부터 버그가 발생하는 것을 피할 수 있으므로 실제로 우리는 통과 할 것으로 예상되는 테스트를 작성합니다 (TDD가 시작되면 OK이지만 실패는 주문 아티팩트 일뿐입니다) 코드가 완성되었으므로 코드에 대해 생각했기 때문에 대부분 전달됩니다.

둘째, 단위 테스트는 리팩토링 할 때 실제로 자체 테스트됩니다. 구현을 변경했지만 답변은 동일하게 유지 될 것으로 예상합니다. 단위 테스트는 인터페이스 계약 위반에 대한 보호입니다. 다시 한 번 테스트 통과를 기대합니다.

이것은 아마도 안정적인 공용 인터페이스의 경우 모든 공용 메소드가 테스트되었음을 ​​알 수 있도록 명확한 이동성이 필요하다는 것을 의미합니다.

당신의 명백한 질문에 대답하기 위해 : 공용 인터페이스를위한 단위 테스트는 가치가 있습니다.

응답 의견에서 편집 :

개인적인 방법을 테스트? 그렇습니다. 그러나 무언가를 테스트하지 않으면 내가 타협해야 할 곳입니다. 결국 공개 방법이 작동하면 개인 문제에서 버그가 그렇게 중요 할 수 있습니까? 실용적으로 이탈은 개인 사물에서 발생하는 경향이 있으며, 공용 인터페이스를 유지하기 위해 열심히 노력하지만, 변경 사항에 의존하는 사적인 사물은 변경 될 수 있습니다. 어떤 시점에서 내부 테스트를 유지 관리하는 것이 많은 노력을 기울일 수 있습니다. 그 노력은 잘 보냈습니까?


테스트를 할 때 퍼블릭 인터페이스 테스트에 초점을 맞추고 있습니까? 그것이 맞다고 가정하면 단위 테스트를 수행하지 않은 개인 메소드 / 인터페이스에 버그를 남길 가능성이 더 높지 않다고 테스트되지 않은 "비공개"인터페이스의 일부 까다로운 버그로 인해 테스트가 통과 될 수 있습니다 정말 실패했을 것입니다. 그렇게 생각하는 것이 잘못입니까?
zcourts

코드 적용 범위를 사용하면 공개 메소드를 테스트하는 동안 개인 메소드의 코드가 실행되지 않는시기를 알 수 있습니다. 공개 메소드가 완전히 포함 된 경우, 발견되지 않은 모든 비공개 메소드는 분명히 사용되지 않으며 제거 할 수 있습니다. 그렇지 않은 경우 공용 메소드에 대한 추가 테스트가 필요합니다.
David Harkness

2

단위 테스트는 더 큰 테스트 전략의 일부 여야합니다. 어떤 유형의 테스트를 작성하고 언제 선택할지 결정하는 데이 원칙을 따릅니다.

  • 엔드 투 엔드 테스트 작성에 중점을 둡니다. 단위 테스트보다 테스트 당 더 많은 코드를 다루므로 벅에 대해 더 많은 테스트를 수행하십시오. 이를 시스템 전체의 자동화 된 검증으로 만드십시오.

  • 복잡한 논리의 덩어리에 대한 단위 테스트 작성으로 넘어갑니다. 엔드-투-엔드 테스트가 적절한 코드 적용 범위를 작성하기 위해 디버그하기 어렵거나 다루기 어려운 상황에서 단위 테스트는 그 가치가 있습니다.

  • 테스트중인 API가 안정적 으로 될 때까지 기다렸다가 두 가지 유형의 테스트를 작성하십시오. 구현과 테스트를 모두 리팩토링하지 않아도됩니다.

롭 애쉬튼 (Rob Ashton) 은이 주제에 관한 훌륭한 기사 를 가지고 있는데 , 나는 위의 원리를 분명히하기 위해 많이 그렸습니다.


+1-모든 요점 (또는 기사의 요점)에 반드시 동의하는 것은 아니지만 맹목적으로 수행하면 대부분의 단위 테스트는 쓸모가 없다는 것입니다 (TDD 방식). 그러나 단위 테스트를 수행하는 데 시간을 투자 할 가치가있는 것을 결정하는 데 현명한 경우에는 매우 가치가 있습니다. 더 높은 수준의 테스트, 특히 하위 시스템 수준의 자동화 된 테스트를 작성하는 데 드는 비용을 훨씬 더 많이들이는 데 동의합니다. 엔드-투-엔드 자동 테스트의 문제점은 시스템이 크기 / 복잡성을 가지고있는 경우 시스템이 완전히 비현실적이지는 않지만 어렵다는 것입니다.
Dunk

0

나는 잘 작동하는 것처럼 보이는 단위 테스트에 대한 다른 접근법을 따르는 경향이 있습니다. 단위 테스트를 "일부 동작 테스트"라고 생각하는 대신 "코드를 따라야하는 사양"이라고 생각합니다. 이런 방식으로, 객체가 특정 방식으로 동작해야한다는 것을 기본적으로 선언 할 수 있으며, 프로그램의 다른 곳에서 버그가 없다고 확신 할 수 있습니다.

공개 API를 작성하는 경우 매우 유용합니다. 그러나 100 % 단위 테스트 범위에 접근하는 것은 일반적으로 그만한 가치가 없으며 단위 테스트 방법 (모의, 기타)

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