단위 테스트 사례를 어떻게 작성합니까?


14

때로는 다른 개발자가 작성한 코드에 대한 단위 테스트 사례를 작성하게됩니다. 개발자가 무엇을하려고하는지 모르는 경우가 있습니다 (사업 부분). 그냥 녹색 라인을 얻기 위해 테스트 케이스를 조작합니다. 업계에서 이런 것들이 정상입니까?

정상적인 추세는 무엇입니까? 개발자는 자신이 작성한 코드에 대한 단위 테스트 사례를 작성해야합니까?


2
"힘"? "dint"는 무엇을 의미합니까?
S.Lott

답변:


12

이 블로그 게시물을 읽으십시오 : 위대한 단위 시험 작성 : 모범 사례 및 최악의 사례 .

그러나 웹에는 수많은 다른 사람들이 있습니다.

귀하의 질문에 직접 대답하여 ...

  1. "정상적인 추세"-이것은 장소마다 다를 수 있다고 생각합니다. 저에게는 정상적인 것이 다른 사람들에게는 이상 할 것입니다.
  2. 코드를 작성하는 개발자는 코드 앞에 테스트를 작성하는 TDD와 같은 방법을 사용하여 테스트를 작성해야한다고 말하고 싶습니다. 그러나 다른 사람들은 여기에 다른 방법과 아이디어가있을 수 있습니다!

그리고 당신이 테스트를 작성하는 방법은 (당신의 질문에) 완전히 잘못되었습니다!


9

이 접근법은 단위 테스트를 무가치하게 만듭니다.

실제 조치가 의도 한대로 작동하지 않으면 단위 테스트에 실패해야합니다. 그렇게하지 않고 테스트 코드 전에 테스트를 작성하면 작동하지 않는 연기 경보가있는 것과 같습니다.


8
이것은 사실이 아닙니다. 오히려 이상적인 세상에서는 사실이지만, 아쉽게도 종종 우리는 그와는 거리가 멀습니다. (이 테스트없이 사양하지 않고, 안정적으로 코드의 특정 조각이 정확하게 어떻게해야 어떤 분 세부 사항에 당신을 말할 수있는 사람이없이 기존의 코드를 고려해 입니다 기존 프로젝트의 큰 비율 현실). 이 경우에도 코드의 현재 상태를 잠그고 향후 리팩토링, 버그 수정 또는 확장 기능으로 문제를 일으키지 않도록 유닛 테스트를 작성하는 것이 좋습니다.
Péter Török

2
또한 " 코드를 테스트 한 후 테스트 작성"을 의미한다고 생각 하십니까?
Péter Török

@ 피터, 문구가 잘못되었습니다-당신이 맞아요. 당신이 쓰기 시험을 결정하는 경우에, 그들은해야 할 일을 유용 할 수 있습니다. 테스트라고 말하는 코드를 맹목적으로 호출하는 것은 테스트가 아니라고 생각 합니다.

ørn, 우리가 단위 테스트에서 의미있는 주장을해야한다는 것을 의미한다면, 테스트 된 코드가 실제로 우리가 생각 하는 대로 작동하는지 확인하기 위해 전적으로 동의합니다.
Péter Török

3

함수가 무엇인지 모른다면 단위 테스트를 작성할 수 없습니다. 당신이 알고있는 것은 심지어 그것이해야 할 일조차하지 않는다는 것을 알고 있습니다. 먼저해야 할 일을 찾아야합니다. 그런 다음 테스트를 작성하십시오.


3

실제 세계에서는 다른 사람의 코드에 대한 단위 테스트를 작성하는 것이 일반적으로 정상입니다. 물론, 원래 개발자는 이미이 작업을 수행 했어야하지만, 아직 완료되지 않은 레거시 코드를받는 경우가 종종 있습니다. 그건 그렇고, 레거시 코드가 수십 년 전에 먼 곳에서 멀리 떨어진 곳에서 왔는지, 아니면 동료 중 한 명이 지난 주에 확인했는지, 또는 오늘 작성한 코드인지 여부는 중요 하지 않습니다. 레거시 코드는 테스트없는 코드입니다

스스로에게 물어보십시오 : 왜 단위 테스트를 작성합니까? Green으로가는 것은 분명히 목적을위한 수단 일뿐입니다. 궁극적 인 목표는 테스트중인 코드에 대한 주장을 증명하거나 반증하는 것입니다.

부동 소수점 숫자의 제곱근을 계산하는 방법이 있다고 가정 해보십시오. Java에서 인터페이스는 다음과 같이 정의합니다.

public double squareRoot(double number);

구현을 작성했는지 또는 다른 사람이 작성했는지는 중요하지 않습니다. squareRoot의 몇 가지 속성을 지정하려고합니다.

  1. sqrt (4.0)과 같은 간단한 뿌리를 반환 할 수 있다는 것
  2. sqrt (2.0)과 같은 실제 근을 합리적인 정밀도로 찾을 수 있다는 것
  3. sqrt (0.0)이 0.0이라는 것을 알았습니다.
  4. 음수를 입력하면 sqrt (-1.0)에서 IllegalArgumentException이 발생합니다.

따라서 이것을 개별 테스트로 작성하기 시작합니다.

@Test
public void canFindSimpleRoot() {
  assertEquals(2, squareRoot(4), epsilon);
}

죄송합니다.이 테스트는 이미 실패했습니다.

java.lang.AssertionError: Use assertEquals(expected, actual, delta) to compare floating-point numbers

부동 소수점 산술을 잊었습니다. 좋아, 당신은 소개 double epsilon=0.01하고 간다 :

@Test
public void canFindSimpleRootToEpsilonPrecision() {
  assertEquals(2, squareRoot(4), epsilon);
}

다른 테스트를 추가하십시오 : 마침내

@Test
@ExpectedException(IllegalArgumentException.class)
public void throwsExceptionOnNegativeInput() {
  assertEquals(-1, squareRoot(-1), epsilon);
}

그리고 또 다시 :

java.lang.AssertionError: expected:<-1.0> but was:<NaN>

다음을 테스트해야합니다.

@Test
public void returnsNaNOnNegativeInput() {
  assertEquals(Double.NaN, squareRoot(-1), epsilon);
}

우리는 여기서 무엇을 했습니까? 우리는 그 방법이 어떻게 동작해야하는지에 대한 몇 가지 가정으로 시작했고, 모든 것이 사실이 아님을 발견했습니다. 그런 다음 수정 된 가정에 따라 방법이 작동한다는 증거를 기록하기 위해 테스트 스위트를 Green으로 만들었습니다. 이제이 코드의 클라이언트는이 동작에 의존 할 수 있습니다. 누군가가 squareRoot의 실제 구현을 다른 것과 교환한다면, 예를 들어 NaN을 반환하는 대신 실제로 예외를 던진 것이 우리의 테스트에서 즉시 포착됩니다.

이 예제는 사소한 것이지만 실제로 실제로 수행하는 작업이 불분명 한 큰 코드 조각을 상속하는 경우가 많습니다. 이 경우 코드 주위에 테스트 장치를 배치하는 것이 일반적입니다. 코드의 작동 방식에 대한 몇 가지 기본 가정부터 시작하여 코드에 대한 단위 테스트를 작성하고 테스트하십시오. 초록색이면 더 많은 테스트를 작성하십시오. 빨간색 인 경우 이제 사양에 대해 유지할 수있는 어설 션이 실패한 것입니다. 레거시 코드에 버그가있을 수 있습니다. 이 특정 입력에 대해서는 사양이 명확하지 않을 수 있습니다. 사양이 없을 수도 있습니다. 이 경우 예기치 않은 동작을 문서화하도록 테스트를 다시 작성하십시오.

@Test
public void throwsNoExceptionOnNegativeInput() {
  assertNotNull(squareRoot(-1)); // Shouldn't this fail?
}

시간이 지남에 따라 코드의 실제 작동 방식을 문서화하고 일종의 코드화 된 사양이되는 테스트 장치가 생깁니다. 레거시 코드를 변경하거나 다른 코드로 바꾸려면 테스트 코드를 사용하여 새 코드가 동일하게 동작하는지 또는 새 코드가 예상되고 제어 된 방식으로 다르게 동작하는지 (예 : 실제로 수정 될 것으로 예상되는 버그 수정). 이 하네스는 첫날에 완성 될 필요는 없지만, 불완전한 하네스를 갖는 것이 하네스를 전혀 갖지 않는 것보다 거의 항상 좋습니다. 하네스를 사용하면 클라이언트 코드를 더 쉽게 작성할 수 있으며, 무언가를 변경할 때 어떤 부분이 깨질 지, 결국에는 어디에서 부러 졌는지 알 수 있습니다.

양식에 필수 필드를 채우는 것처럼 단위 테스트를 작성해야한다는 사고 방식에서 벗어나야합니다. 그리고 빨간색 선을 녹색으로 만들기 위해 단위 테스트를 작성해서는 안됩니다. 단위 테스트는 적이 아니며 단위 테스트는 친구입니다.


1

테스트 사례 (프린터)를 작성할 때 각 작은 구성 요소를 생각하려고 시도합니다. 예를 들어, 스캐너가 어떤 명령을 사용하는지 (pjl printer-job-language에서) 모든 기능을 테스트하기 위해 작성할 수있는 것을 말하겠습니다. 이제는 어떻게해야할까요?

각 주요 구성 요소마다 그렇게하려고하지만 하드웨어가 아닌 소프트웨어와 관련하여 각 방법 / 기능을보고 경계를 확인하고 싶습니다.


1

단위 테스트를 수행하지 않는 다른 개발자와 작업하거나 다른 개발자가 작성한 코드를 유지 관리하는 것처럼 들립니다. 이 경우 테스트하려는 객체 또는 메소드가 무엇을 해야하는지 알고 싶고 테스트를 작성해야한다고 생각합니다.

테스트를 먼저 작성하지 않았기 때문에 TDD가 아니지만 상황을 개선 할 수 있습니다. 스텁을 사용하여 테스트중인 오브젝트의 사본을 작성하여 코드가 실패 할 때 테스트가 제대로 작동하는지 확인할 수도 있습니다.

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