단위 테스트를 처음 사용하는 경우 훌륭한 테스트를 작성하는 방법은 무엇입니까? [닫은]


267

단위 테스트 세계에 익숙하지 않아 이번 주에 기존 앱에 대한 테스트 범위를 추가하기로 결정했습니다.

이것은 테스트 할 클래스의 수는 많지만 테스트 작성은 모두 나에게 새롭기 때문에 큰 작업입니다.

이미 여러 클래스에 대한 테스트를 작성했지만 지금 제대로하고 있는지 궁금합니다.

메소드에 대한 테스트를 작성할 때 메소드 자체에 이미 쓴 내용을 두 번 다시 쓰는 느낌이 듭니다.
내 테스트는 메소드에 너무 밀접하게 묶여있는 것 같습니다 (모든 인수를 사용하여 일부 내부 메소드가 여러 번 호출 될 것으로 예상하는 모든 코드 경로 테스트). 메소드를 리팩터링하면 테스트가 실패하더라도 방법의 최종 행동은 변하지 않았다.

이것은 단지 느낌 일 뿐이며 앞서 말한 것처럼 테스트 경험이 없습니다. 경험이 풍부한 테스터 중 일부가 기존 앱에 대해 훌륭한 테스트를 작성하는 방법에 대한 조언을 제공 할 수 있다면 크게 감사하겠습니다.

편집 : Stack Overflow에 감사 드리고 싶습니다 .15 분도 채 안되는 시간 동안 온라인에서 읽은 시간보다 더 많은 답변을 얻었습니다.


1
다음은 단위 테스트를위한 최상의 책입니다. manning.com/osherove 이 문서는 단위 테스트를위한 모든 모범 사례, 수행 및 금지 사항 에 대해 설명합니다.
Ervi B

이 모든 대답에서 빠뜨린 한 가지는 단위 테스트가 문서와 같다는 것입니다. Ergo, 함수를 작성하면 입력 및 출력 (및 부작용)을 설명하여 의도를 문서화합니다. 그런 다음 단위 테스트를 통해이를 확인해야합니다. 그리고 나중에 (또는 다른 사람이) 코드를 변경하면 문서는 변경 가능한 사항의 경계를 설명해야하며 단위 테스트를 통해 경계가 유지되는지 확인해야합니다.
Thomas Tempelmann

답변:


187

내 테스트는 메소드에 너무 밀접하게 묶여있는 것 같습니다 (모든 인수를 사용하여 일부 내부 메소드가 여러 번 호출 될 것으로 예상하는 모든 코드 경로 테스트). 메소드를 리팩터링하면 테스트가 실패하더라도 테스트가 실패하는 것처럼 보입니다. 방법의 최종 행동은 변하지 않았다.

당신이 잘못하고 있다고 생각합니다.

단위 테스트는 다음을 수행해야합니다.

  • 하나의 방법을 테스트
  • 그 방법에 대한 특정 주장을 제공
  • 결과가 예상대로인지 테스트

내부를 변경하면 테스트가 실패하지 않아야합니다. 개인 메소드가 호출되는지 직접 테스트해서는 안됩니다. 개인 코드를 테스트하고 있는지 확인하려면 코드 범위 도구를 사용하십시오. 그러나이 점에 집착하지 마십시오. 100 % 적용 범위는 필수 사항이 아닙니다.

메소드가 다른 클래스의 공용 메소드를 호출하고 이러한 호출이 인터페이스에 의해 보장되는 경우 모의 프레임 워크를 사용하여 이러한 호출이 수행되고 있는지 테스트 할 수 있습니다.

예상되는 결과를 동적으로 생성하기 위해 메소드 자체 (또는 메소드가 사용하는 내부 코드)를 사용해서는 안됩니다. 예상 결과는 구현이 변경 될 때 변경되지 않도록 테스트 케이스에 하드 코딩되어야합니다. 다음은 단위 테스트의 간단한 예입니다.

testAdd()
{
    int x = 5;
    int y = -2;
    int expectedResult = 3;
    Calculator calculator = new Calculator();
    int actualResult = calculator.Add(x, y);
    Assert.AreEqual(expectedResult, actualResult);
}

결과 계산 방법은 확인되지 않으며 결과 만 정확합니다. 가능한 한 많은 시나리오를 다룰 때까지 위와 같이 더 간단한 테스트 사례를 계속 추가하십시오. 코드 커버리지 도구를 사용하여 흥미로운 경로를 놓쳤는 지 확인하십시오.


13
고마워요. 대답이 더 완전 했어요. 이제 모의 객체가 실제로 무엇인지 이해하는 것이 좋습니다. 다른 메소드를 호출 할 필요가 없습니다. 관련 메소드 만 호출하면됩니다. 또한 일이 어떻게 수행되는지 알 필요는 없지만 올바르게 수행됩니다.
pixelastic

2
정중하게 당신 이 잘못하고 있다고 생각 합니다 . 단위 테스트는 코드 실행 흐름에 관한 것입니다 (화이트 박스 테스트). 블랙 박스 테스트 (제안한 것)는 일반적으로 기능 테스트 (시스템 및 통합 테스트)에 사용되는 기술입니다.
Wes

1
"단위 테스트는 한 가지 방법을 테스트해야합니다"나는 실제로 동의하지 않습니다. 단위 테스트는 하나의 논리적 개념을 테스트해야합니다. 그것은 종종 하나의 방법으로 표현되지만, 항상 그런 것은 아닙니다
robertmain

35

단위 테스트의 경우 Test Driven (첫 번째 테스트, 코드 두 번째)과 code first (테스트 두 번째)가 모두 유용하다는 것을 알았습니다.

코드를 작성하고 테스트를 작성하는 대신. 코드를 작성하고 코드가해야 할 일을 살펴보십시오. 의도 된 모든 용도에 대해 생각한 다음 각각에 대한 테스트를 작성하십시오. 코딩 테스트보다 코딩 테스트가 더 빠르지 만 더 복잡합니다. 테스트는 의도를 테스트해야합니다. 또한 시험 작문 단계에서 코너 케이스를 찾는 의도에 대해 생각하십시오. 그리고 물론 테스트를 작성하는 동안 몇 가지 용도 중 하나가 버그를 일으키는 것을 알 수 있습니다.

그러나 테스트는 거의 두 번 코딩하는 것과 같습니다. 실제로 응용 프로그램 코드보다 테스트 코드 (수량)가 더 많은 응용 프로그램이 있습니다. 하나의 예는 매우 복잡한 상태 머신입니다. 더 많은 로직을 추가 한 후 모든 것이 항상 이전의 모든 유스 케이스에서 작동했는지 확인해야했습니다. 그리고 코드를 살펴보면 이러한 경우를 따르기가 매우 어려웠으므로 변경을 한 후에도 중단되지 않을 것이라고 확신하는이 컴퓨터에 적합한 테스트 스위트를 갖추었고 테스트 결과 내 엉덩이가 몇 번 절약되었습니다. . 그리고 사용자 나 테스터가 설명되지 않은 흐름 또는 코너 사례로 버그를 발견함에 따라 무엇을 테스트하고 테스트에 추가했으며 다시는 발생하지 않았 음을 추측하십시오. 이것은 정말로 모든 것을 매우 안정적으로 만드는 것 외에도 사용자에게 내 작업에 대한 자신감을 주었다. 성능상의 이유로 다시 작성해야했을 때

모든 간단한 예제 function square(number)는 훌륭하고 모두 테스트에 많은 시간을 할애 할 수 있습니다. 중요한 비즈니스 로직을 수행하는 것, 테스트가 중요한 것. 요구 사항을 테스트하십시오. 배관 테스트 만하지 마십시오. 요구 사항이 바뀌면 무엇을 추측해야하는지 테스트도해야합니다.

테스트는 문자 foo를 호출 한 함수 표시 줄을 3 번 테스트하는 것이 아닙니다. 그건 잘못이야 내부 역학이 아닌 결과와 부작용이 올바른지 확인하십시오.


2
좋은 대답은 코드 후에 테스트를 작성하는 것이 여전히 유용하고 가능하다는 확신을주었습니다.
pixelastic

2
완벽한 최근 예. 나는 매우 간단한 기능을 가지고있었습니다. 사실을 전달하고, 한 가지 일을하고, 다른 일을하는 것은 거짓입니다. 매우 간단합니다. 함수가 의도 한 기능을 수행하는지 확인하기 위해 4 가지 테스트를 수행했습니다. 나는 행동을 조금 바꾼다. 테스트를 실행하고 문제를 해결하십시오. 재미있는 점은 응용 프로그램을 사용할 때 문제가 나타나지 않는 복잡한 경우에만 나타납니다. 테스트 사례에서이를 발견하고 몇 시간의 두통을 피했습니다.
Dmitriy Likhten

"테스트는 의도를 테스트해야합니다." 이것으로 요약하면 코드의 의도 된 용도를 거쳐 코드가 코드를 수용 할 수 있는지 확인해야합니다. 또한 테스트에서 실제로 테스트해야하는 범위와 코드를 변경할 때 변경 사항이 규정 된 코드의 모든 용도에 영향을 미치는 방식을 고려하지 않을 수 있다는 생각을 나타냅니다. 의도 된 모든 사용 사례를 충족하지 않는 변경을 방지합니다.
Greenstick

18

기존 코드에 개장 단위 테스트를 수정하는 것이 처음에 테스트로 코드를 작성하는 것보다 훨씬 어렵다는 점에 주목할 가치가 있습니다. 레거시 응용 프로그램을 다루는 데있어 가장 큰 질문 중 하나입니다. 단위 테스트 방법? 이것은 여러 번 전에 요청되었으므로 (질문 과 같은 질문으로 닫힐 있음) 사람들은 보통 여기에 있습니다.

기존 코드를 테스트 중심 개발로 이동

나는 받아 들인 답변의 책 추천을 두 번째로 넘어서지 만 그 외에도 답변에 연결된 더 많은 정보가 있습니다.


3
첫 번째 또는 두 번째 테스트를 작성하면 문제가 없지만 테스트를 작성할 때는 테스트를 작성할 수 있도록 코드를 테스트 할 수 있는지 확인하십시오. "어떻게 테스트 할 수 있을까요?"라는 생각을 자주하면 더 나은 코드를 작성하게됩니다. 테스트 케이스 개조는 항상 큰 문제가되지 않습니다. 열심히. 시간 문제가 아니며 수량 및 테스트 가능성 문제입니다. 나는 지금 상사에게 다가 갈 수 없으며 수천 개가 넘는 테이블과 용도에 대한 테스트 사례를 작성하고 싶다고 말하면서 너무 오래 걸리고 1 년이 걸리고 일부 논리 / 결정은 잊혀졌습니다. 너무 길게
치지 마십시오

2
아마도 허용 된 답변이 변경되었을 것입니다. Linx의 답변은 Roy Osherove ( manning.com/osherove
thelem)의

15

코드를 완전히 다루기 위해 테스트를 작성하지 마십시오. 요구 사항을 보장하는 테스트를 작성하십시오. 불필요한 코드 경로를 발견 할 수 있습니다. 반대로, 필요한 경우, 어떤 종류의 요구 사항을 충족해야합니다. 그것이 무엇인지 찾고 요구 사항을 테스트하십시오 (경로 아님).

테스트는 작게 유지하십시오 (요구 사항 당 하나의 테스트).

나중에 변경하거나 새 코드를 작성해야 할 경우 먼저 하나의 테스트를 작성하십시오. 딱 하나만. 그런 다음 테스트 중심 개발의 첫 단계를 밟게됩니다.


감사합니다. 작은 요구 사항에 대해 한 번에 하나씩 작은 테스트 만 수행하는 것이 좋습니다. 교훈을 얻었습니다.
pixelastic

13

단위 테스트는 함수 / 메소드 / 애플리케이션에서 얻은 출력에 대한 것입니다. 결과가 어떻게 생성되는지는 중요하지 않으며 결과가 정확하다는 것만 중요합니다. 따라서 내부 메소드에 대한 호출을 계산하는 방식은 잘못되었습니다. 내가하는 경향은 앉아서 특정 입력 값이나 특정 환경에서 메소드가 반환 해야하는 것을 작성한 다음 반환 된 실제 값과 내가 얻은 것과 비교하는 테스트를 작성하는 것입니다.


감사 ! 나는 내가 잘못하고 있다고 생각했지만 실제로 누군가 나에게 말하는 것이 더 좋습니다.
pixelastic

8

테스트 할 메소드를 작성하기 전에 단위 테스트를 작성하십시오.

그렇게하면 일이 어떻게 진행되고 있는지에 대해 조금 다르게 생각하게 될 것입니다. 방법이 어떻게 작동하는지, 어떻게해야하는지 전혀 모를 것입니다.

메소드가 결과를 얻는 방법이 아니라 항상 메소드 결과를 테스트해야합니다.


예, 방법이 이미 작성되어있는 것을 제외하고는 그렇게 할 수 있기를 바랍니다. 그냥 테스트하고 싶습니다. 앞으로 메소드 앞에 테스트를 작성하겠습니다.
pixelastic

2
@pixelastic은 방법이 작성되지 않은 척?
committedandroider

4

테스트는 유지 관리 성을 향상시켜야합니다. 방법을 변경하고 테스트를 중단 하면 좋은 결과가 될 있습니다. 반면에, 메소드를 블랙 박스로 보면 메소드 내부의 내용이 중요하지 않습니다. 사실 일부 테스트를 위해 조롱해야하며,이 경우 실제로 방법을 블랙 박스로 취급 할 수 없습니다. 통합 테스트를 작성하는 것이 유일한 방법입니다. 테스트중인 서비스의 완전히 인스턴스화 된 인스턴스를로드하고 앱에서 실행되는 것과 같은 방식으로 수행하십시오. 그런 다음 블랙 박스로 취급 할 수 있습니다.

When I'm writing tests for a method, I have the feeling of rewriting a second time what I          
already wrote in the method itself.
My tests just seems so tightly bound to the method (testing all codepath, expecting some    
inner methods to be called a number of times, with certain arguments), that it seems that
if I ever refactor the method, the tests will fail even if the final behavior of the   
method did not change.

코드를 작성한 후 테스트를 작성하기 때문입니다. 다른 방법으로 테스트를 수행했다면 (먼저 테스트를 작성하십시오) 이런 느낌이 들지 않습니다.


블랙 박스 예제에 감사드립니다. 그렇게 생각하지 않았습니다. 단위 테스트를 일찍 발견했지만 불행히도 그렇지 않습니다 . 테스트를 추가하기 위해 레거시 앱이 붙어 있습니다. 테스트를 중단하지 않고 기존 프로젝트에 테스트를 추가 할 수있는 방법이 없습니까?
pixelastic

1
이후의 필기 시험은 이전의 필기 시험과 다르므로 문제가 있습니다. 그러나 할 수있는 일은 먼저 실패하도록 테스트를 설정 한 다음 클래스를 테스트에 넣음으로써 통과시킵니다 .... 테스트가 실패한 후에 인스턴스를 테스트에 넣는 것과 같은 작업을 수행하십시오. 모의의 경우와 동일합니다. 처음에는 모의에 대한 기대치가 없으며 테스트중인 메소드가 모의로 무언가를 수행 한 다음 테스트를 통과하기 때문에 실패합니다. 이 방법으로 많은 버그를 발견해도 놀라지 않을 것입니다.
hvgotcodes

또한 귀하의 기대에 구체적으로 기재하십시오. 테스트가 객체를 반환한다고 주장하지 말고 객체에 다양한 값이 있는지 테스트하십시오. 값이 널 (null)이어야하는지 테스트하십시오. 또한 테스트를 추가 한 후 수행하려는 리팩토링을 수행하여 약간 분리 할 수도 있습니다.
hvgotcodes
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.