단위 테스트로 무엇을 테스트해야합니까?


122

나는 대학에서 신입생이고 다음 주 어딘가에 대학을 시작합니다. 우리는 단위 테스트를 보았지만 많이 사용하지는 않았습니다. 모두가 그들에 대해 이야기하기 때문에 아마도 내가해야 할 일이라고 생각했습니다.

문제는 무엇 을 테스트 해야할지 모르겠다는 입니다. 일반적인 경우를 테스트해야합니까? 가장자리 사건? 기능이 적절하게 적용되었다는 것을 어떻게 알 수 있습니까?

나는 항상 테스트가 어떤 경우에는 함수가 작동한다는 것을 증명하지만, 그 함수가 작동한다는 것을 증명하는 것은 전혀 쓸모가 없다는 끔찍한 느낌을 가지고 있습니다.


Roy Osherove의 블로그를 살펴보십시오 . 비디오를 포함하여 단위 테스트에 대한 많은 정보가 있습니다. 그는 또한 "단위 테스팅 기술"이라는 책을 썼습니다.
Piers Myers

9
거의 5 년 후에 어떻게 생각하십니까? 요즘 사람들은 "무엇을 테스트하지 말아야하는지"를 더 잘 알아야한다고 생각하기 때문입니다. 행동 주도 개발은 귀하가 요청한 것과 같은 질문에서 발전했습니다.
Remigijus Pankevičius

답변:


121

나의 개인적인 철학은 지금까지 :

  1. 할 수있는 모든 일의 일반적인 사례를 테스트하십시오. 이것은 약간의 변경을 한 후에 코드가 중단되는 시점을 알려줄 것입니다.
  2. 오류가있을 것으로 생각되는 비정상적으로 복잡한 몇 가지 코드의 에지 사례를 테스트하십시오.
  3. 버그를 발견 할 때마다 수정하기 전에 테스트 케이스를 작성하여 커버하십시오.
  4. 누군가 죽일 시간이있을 때마다 덜 중요한 코드에 엣지 케이스 테스트를 추가하십시오.

1
감사합니다. OP와 같은 질문으로 여기에 푹 빠져있었습니다.
Stephen

5
+1이지만 라이브러리 / 유틸리티 유형 함수의 엣지 사례를 테스트하여 논리적 API가 있는지 확인합니다. 예를 들어 null이 전달되면 어떻게됩니까? 빈 입력은 어떻습니까? 이를 통해 디자인이 논리적이고 코너 케이스 동작을 문서화 할 수 있습니다.
mikera 2016 년

7
# 3은 단위 테스트가 어떻게 도움이되었는지에 대한 실제 사례이므로 매우 확실한 대답처럼 보입니다. 한 번 파손되면 다시 파손될 수 있습니다.
라이언 그리피스

방금 시작한 나는 시험을 고안하는 데 독창적이지 않다는 것을 알았습니다. 따라서 위의 # 3으로 사용하면 버그가 다시 발견되지 않을 것이라는 안심할 수 있습니다.
ankush981

귀하의 답변은이 인기있는 중간 기사에 실 렸습니다 : hackernoon.com/…
BugHunterUK

67

지금까지 과다한 답변 중 동등성 분할경계 값 분석 에 대해서는 아직 아무도 다루지 않았습니다 . 다른 모든 대답은 유용하지만 질적이지만 여기서는 정량적 일 수 있습니다. @fishtoaster는 테스트 정량화의 커버를 통해 엿보기에 대한 구체적인 지침을 제공하지만 동등성 분할 및 경계 값 분석을 통해 더 나은 결과를 얻을 수 있습니다.

동등성 파티셔닝 에서는 가능한 모든 입력 세트를 예상 결과에 따라 그룹으로 나눕니다. 한 그룹의 모든 입력은 동등한 결과를 생성하므로 이러한 그룹을 동등성 클래스 라고 합니다 . 동등한 결과가 동일한 결과를 의미 하지는 않습니다 .

간단한 예로 소문자 ASCII 문자를 대문자로 변환해야하는 프로그램을 고려하십시오. 다른 캐릭터는 신원 변환을 거쳐야합니다. 동등성 클래스로 분류 할 수있는 방법은 다음과 같습니다.

| # |  Equivalence class    | Input        | Output       | # test cases |
+------------------------------------------------------------------------+
| 1 | Lowercase letter      | a - z        | A - Z        | 26           |
| 2 | Uppercase letter      | A - Z        | A - Z        | 26           |
| 3 | Non-alphabetic chars  | 0-9!@#,/"... | 0-9!@#,/"... | 42           |
| 4 | Non-printable chars   | ^C,^S,TAB... | ^C,^S,TAB... | 34           |

마지막 열은 모든 테스트 사례를 열거하면 테스트 사례 수를보고합니다. 기술적으로 @fishtoaster의 규칙 1에서는 52 개의 테스트 사례를 포함합니다. 위에 제공된 처음 두 행에 대한 모든 사례는 "일반 사례"에 해당합니다. @fishtoaster의 규칙 2는 위의 행 3과 4에서 일부 또는 전부를 추가합니다. 그러나 동등성 분할 테스트 에서는 각 동등성 클래스에서 하나의 테스트 케이스로 충분합니다. "a"또는 "g"또는 "w"를 선택하면 동일한 코드 경로를 테스트하는 것입니다. 따라서 52 개가 아닌 총 4 개의 테스트 사례가 있습니다.

경계 값 분석 은 약간의 개선을 권장합니다. 본질적으로 동등성 클래스의 모든 구성원이 동등하지는 않다는 것을 제안합니다. 즉, 경계의 값도 자체적으로 테스트 사례에 적합한 것으로 간주해야합니다. (이것에 대한 하나의 쉬운 정당화는 악명 높은 off-by-one error입니다 !) 따라서 각 동등성 클래스에 대해 3 개의 테스트 입력을 가질 수 있습니다. 위의 입력 도메인과 ASCII 값에 대한 지식을 살펴보면 다음과 같은 테스트 케이스 입력을 얻을 수 있습니다.

| # | Input                | # test cases |
| 1 | a, w, z              | 3            |
| 2 | A, E, Z              | 3            |
| 3 | 0, 5, 9, !, @, *, ~  | 7            |
| 4 | nul, esc, space, del | 4            |

(원래 동등성 클래스 묘사를 다시 생각하고 싶을 수있는 3 개 이상의 경계 값을 얻 자마자 이것은 간단하게 수정하기 위해 되돌아 가지 않았습니다.) 따라서 경계 값 분석은 우리에게 단지 철저한 테스트를 수행하기위한 128 개의 테스트 사례와 비교하여 완벽한 적용 범위를 보장하는 17 개의 테스트 사례. (조합론에 따르면 철저한 테스트는 실제 응용 프로그램에서는 불가능하다고 말할 수는 없습니다!)


3
+1 정확히 직관적으로 테스트를 작성하는 방법입니다. 이제 그것에 이름을 붙일 수 있습니다 :) 공유해 주셔서 감사합니다.
guillaume31

+1 "질적 대답은 유용하지만, 그것은 가능하다 - 그리고 바람직 - 양적으로"
지미 브렉-McKye

지시문이 "내 테스트를 어떻게 잘 적용 할 수 있습니까?"인 경우 이것이 좋은 대답이라고 생각합니다. 나는 이것에 대한 실용적인 접근 방식을 찾는 것이 도움이 될 것이라고 생각합니다-모든 계층에서 모든 로직의 모든 브랜치 가이 방식으로 철저히 테스트되어야한다는 목표입니까?
Kieren Johnstone

18

아마 내 의견은 너무 인기가 없습니다. 그러나 단위 테스트를 통해 경제적 일 것을 제안합니다. 단위 테스트가 너무 많으면 실제 코딩이 아닌 테스트를 유지 관리하는 데 시간의 절반 이상을 쉽게 소비 할 수 있습니다.

장에 기분이 나쁘거나 매우 중요하거나 초등적인 것들에 대한 테스트를 작성하는 것이 좋습니다. IMHO 단위 테스트는 우수한 엔지니어링 및 방어 코딩을 대체하지 않습니다. 현재 나는 다소 쓸모없는 프로젝트를 진행하고 있습니다. 정말 안정적이지만 리팩토링하는 데 어려움이 있습니다. 실제로 1 년 안에 아무도이 코드를 건드리지 않았으며 그 기반이되는 소프트웨어 스택은 4 살입니다. 왜? 단위 테스트가 복잡하기 때문에 단위 테스트와 자동화 된 통합 테스트가 정확합니다. (오이 등을 들어 본 적이 있습니까?) 그리고 가장 중요한 부분은 다음과 같습니다.이 (아직) 사용 불가능한이 소프트웨어는 직원들이 테스트 중심 개발 현장에서 개척자 인 회사에 의해 개발되었습니다. :디

그래서 내 제안은 다음과 같습니다.

  • 기본 스켈레톤을 개발 한 후 테스트 작성을 시작하십시오 . 그렇지 않으면 리팩토링이 어려울 수 있습니다. 다른 사람을 위해 개발하는 개발자는 처음부터 요구 사항을 절대 얻지 못합니다.

  • 단위 테스트를 빠르게 수행 할 수 있는지 확인하십시오. 오이와 같은 통합 테스트가 있다면 조금 더 오래 걸리더라도 괜찮습니다. 그러나 장기 테스트는 재미가 없습니다. (사람들은 C ++이 인기를 얻지 못한 모든 이유를 잊어 버립니다 ...)

  • 이 TDD를 TDD 전문가에게 맡기십시오.

  • 그리고 예, 때로는 예상치 못한 부분에 따라 에지 케이스에, 때로는 일반적인 케이스에 집중하기도합니다. 항상 예상치 못한 결과를 예상하더라도 워크 플로우와 훈련을 다시 생각해야합니다. ;-)


2
테스트로 인해이 소프트웨어가 리팩토링하기 어려운 이유에 대해 더 자세히 설명 할 수 있습니까?
마이크 파트 리지

6
큰 +1. 규칙 대신 구현을 테스트하는 단위 테스트 벽이 있으면 변경에 2-3
배가

9
잘못 작성된 생산 코드와 같이 잘못 작성된 단위 테스트는 유지하기가 어렵습니다. "너무 많은 단위 테스트"는 DRY를 유지하지 못하는 것처럼 들립니다. 각 테스트는 시스템의 특정 부분을 다루거나 증명해야합니다.
Allan

1
각 단위 테스트는 한 가지 사항을 확인해야하므로 단위 테스트가 너무 많지 않고 테스트가 누락됩니다. 단위 테스트가 복잡한 경우 이는 또 다른 문제입니다.
graffic

1
-1 :이 글이 잘못 작성되었다고 생각합니다. 언급 된 여러 가지가 있으며 모두 어떻게 관련되어 있는지 모르겠습니다. 대답의 요점이 "경제적"이라면, 당신의 예는 전혀 어떤 관련이 있습니까? 실제 상황은 좋지만 단위 테스트가 나쁜 것처럼 들립니다. 내가 배워야 할 교훈과 그것이 경제에 도움이되는 방법을 설명하십시오. 또한 솔직히 말하면 당신이 말할 때 당신이 무엇을 의미하는지 모르겠습니다 Leave this TDD stuff to the TDD-experts.
Alexander Bird

8

Test Driven Development로 먼저 테스트하는 경우, 실패한 단위 테스트를 먼저 작성하지 않고 기능을 추가하지 않기 때문에 적용 범위가 90 % 이상이 될 것입니다.

사실 후에 테스트를 추가하는 경우 Michael Feathers의 레거시 코드효과적으로 작업하기 사본을 얻고 코드 에 테스트를 추가하는 방법과 코드를 리팩터링하는 방법을 살펴볼 수는 없습니다. 더 테스트 가능하게 만들기 위해.


해당 커버리지 비율을 어떻게 계산합니까? 어쨌든 코드의 90 %를 커버한다는 것은 무엇을 의미합니까?
zneak

2
@zneak : 코드 커버리지 도구가 있습니다. "코드 범위"에 대한 빠른 구글은 그 중 다수를 가져와야합니다. 이 도구는 테스트를 실행하는 동안 실행되는 코드 줄을 추적하고 어셈블리의 전체 코드 줄을 비판하여 적용 범위 비율을 산출합니다.
Steven Evers

-1. 질문에 대답하지 않습니다 :The problem is, I don't know _what_ to test
Alexander Bird

6

테스트 주도 개발 관행을 따르기 시작 하면 프로세스를 안내 하고 테스트 대상을 자연스럽게 알 수 있습니다. 시작해야 할 곳 :

테스트 우선

절대로 테스트를 작성하기 전에 코드를 작성하지 마십시오. 자세한 내용은 빨강 녹색 리 팩터 반복 을 참조하십시오 .

회귀 테스트 작성

버그가 발생할 때마다 테스트 케이스를 작성하고 실패 했는지 확인하십시오 . 실패한 테스트 케이스를 통해 버그를 재현 할 수 없다면 실제로 찾지 못했습니다.

적녹 리 팩터-반복

빨간색 : 구현하려는 동작에 대한 가장 기본적인 테스트를 작성하여 시작하십시오. 작업중인 클래스 또는 함수를 사용하는 예제 코드를 작성할 때이 단계를 생각하십시오. 컴파일 / 구문 오류가없고 실패 하는지 확인하십시오 . 이것은 분명해야합니다. 코드를 작성하지 않았으므로 실패해야합니까? 여기서 배워야 할 중요한 점은 테스트가 한 번 이상 실패하는 것을 보지 않는 한 테스트가 통과 한 경우 가짜 이유 때문에 수행 한 작업으로 인해 수행된다는 것을 절대 확신 할 수 없다는 것입니다.

녹색 : 실제로 테스트를 통과시키는 가장 단순하고 멍청한 코드를 작성하십시오. 똑똑하지 마십시오. 명백한 경우가 있지만 테스트에서 고려해야 할 사항이 있음에도 불구 하고 처리하기 위해 코드를 작성 하지 마십시오 (단, 경우를 잊지 마십시오 : 나중에 필요할 것입니다). 아이디어는 요 쓰기 모든 코드는 모든이 있다는 것입니다 if, 모든이 try: ... except: ...테스트 케이스에 의해 정당화되어야한다. 코드가 우아하거나 빠르거나 최적화 될 필요는 없습니다. 당신은 시험에 합격하기를 원합니다.

리 팩터 : 코드를 정리하고 메소드 이름을 올바르게 가져 오십시오. 테스트가 여전히 통과하고 있는지 확인하십시오. 최적화하십시오. 테스트를 다시 실행하십시오.

반복 : 테스트에서 다루지 않은 중요한 사례를 기억하십니까? 이제 큰 순간입니다. 해당 상황을 다루는 테스트 케이스를 작성하고, 실패한 것을보고, 코드를 작성하고, 전달, 리팩터링을보십시오.

테스트 당신의 코드를

특정 코드 조각을 작업 중이며 정확하게 테스트하려는 것입니다. 이것은 라이브러리 함수, 표준 라이브러리 또는 컴파일러를 테스트해서는 안됨을 의미합니다. 또한 "세계"테스트를 피하십시오. 여기에는 다음이 포함됩니다 : 외부 웹 API 호출, 일부 데이터베이스 집약적 요소 등


1
기존의 작업 코드 기반이 이미 있다고 가정하면 어떻게해야합니까?
zneak

코드 작성 방법에 따라 약간 더 어려울 수 있습니다. 회귀 테스트 (항상 의미가 있음)로 시작한 다음 단위 테스트를 작성하여 코드의 기능을 이해하고 있음을 증명할 수 있습니다. 해야 할 일의 양에 압도 당하기 쉽지만, 일부 테스트는 항상 테스트가없는 것보다 낫습니다.
Ryszard Szopa

3
-1 나는 이것이이 질문에 대한 좋은 대답이라고 생각하지 않습니다 . 문제는 TDD에 관한 것이 아니라 단위 테스트를 작성할 때 무엇 을 테스트 해야하는지 묻는 것입니다 . 실제 질문에 대한 좋은 대답은 비 TDD 방법론에 적용되어야한다고 생각합니다.
Bryan Oakley

1
만지면 테스트하십시오. Clean Code (Robert C Martin)는 타사 코드에 대한 "학습 테스트"를 작성하도록 제안합니다. 그렇게하면 사용법을 배우고 새 버전이 사용중인 동작을 변경하는 경우 테스트를받습니다.
Roger Willcocks

3

단위 테스트의 경우 의도 한 기능을 수행하는지 테스트로 시작하십시오. 가장 먼저 쓰는 것이 좋습니다. 디자인의 일부가 "정크를 건네면 예외를 던져야"하는 경우, 디자인의 일부이므로이를 테스트하십시오.

그것부터 시작하십시오. 가장 기본적인 테스트를 수행 한 경험이 있으면 테스트가 충분한 지 배우기 시작하고 테스트가 필요한 코드의 다른 측면을보기 시작합니다.


0

주된 답변은 "깨질 수있는 모든 것을 테스트하는 것" 입니다.

깨기에는 너무 간단한 것이 무엇입니까? 데이터 필드, 브레인 데드 속성 접근 자 및 유사한 상용구 오버 헤드 다른 어떤 것도 요구 사항의 식별 가능한 일부를 구현하며 테스트를 통해 이익을 얻을 수 있습니다.

물론, 마일리지와 작업 환경의 관행은 다를 수 있습니다.


괜찮아. 어떤 경우를 테스트해야합니까? "정상적인"사건? 가장자리 사건?
zneak

3
경험의 법칙? 하나 또는 두 개는 황금빛 길의 한가운데, 가장자리 안팎에 있습니다.
Jeffrey Hantin

@JeffreyHantin 그것은 다른 답변에서 "경계 값 분석"입니다.
Roger Willcocks
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.