때로는 다른 개발자가 작성한 코드에 대한 단위 테스트 사례를 작성하게됩니다. 개발자가 무엇을하려고하는지 모르는 경우가 있습니다 (사업 부분). 그냥 녹색 라인을 얻기 위해 테스트 케이스를 조작합니다. 업계에서 이런 것들이 정상입니까?
정상적인 추세는 무엇입니까? 개발자는 자신이 작성한 코드에 대한 단위 테스트 사례를 작성해야합니까?
때로는 다른 개발자가 작성한 코드에 대한 단위 테스트 사례를 작성하게됩니다. 개발자가 무엇을하려고하는지 모르는 경우가 있습니다 (사업 부분). 그냥 녹색 라인을 얻기 위해 테스트 케이스를 조작합니다. 업계에서 이런 것들이 정상입니까?
정상적인 추세는 무엇입니까? 개발자는 자신이 작성한 코드에 대한 단위 테스트 사례를 작성해야합니까?
답변:
이 블로그 게시물을 읽으십시오 : 위대한 단위 시험 작성 : 모범 사례 및 최악의 사례 .
그러나 웹에는 수많은 다른 사람들이 있습니다.
귀하의 질문에 직접 대답하여 ...
그리고 당신이 테스트를 작성하는 방법은 (당신의 질문에) 완전히 잘못되었습니다!
이 접근법은 단위 테스트를 무가치하게 만듭니다.
실제 조치가 의도 한대로 작동하지 않으면 단위 테스트에 실패해야합니다. 그렇게하지 않고 테스트 코드 전에 테스트를 작성하면 작동하지 않는 연기 경보가있는 것과 같습니다.
함수가 무엇인지 모른다면 단위 테스트를 작성할 수 없습니다. 당신이 알고있는 것은 심지어 그것이해야 할 일조차하지 않는다는 것을 알고 있습니다. 먼저해야 할 일을 찾아야합니다. 그런 다음 테스트를 작성하십시오.
실제 세계에서는 다른 사람의 코드에 대한 단위 테스트를 작성하는 것이 일반적으로 정상입니다. 물론, 원래 개발자는 이미이 작업을 수행 했어야하지만, 아직 완료되지 않은 레거시 코드를받는 경우가 종종 있습니다. 그건 그렇고, 레거시 코드가 수십 년 전에 먼 곳에서 멀리 떨어진 곳에서 왔는지, 아니면 동료 중 한 명이 지난 주에 확인했는지, 또는 오늘 작성한 코드인지 여부는 중요 하지 않습니다. 레거시 코드는 테스트 가 없는 코드입니다
스스로에게 물어보십시오 : 왜 단위 테스트를 작성합니까? Green으로가는 것은 분명히 목적을위한 수단 일뿐입니다. 궁극적 인 목표는 테스트중인 코드에 대한 주장을 증명하거나 반증하는 것입니다.
부동 소수점 숫자의 제곱근을 계산하는 방법이 있다고 가정 해보십시오. Java에서 인터페이스는 다음과 같이 정의합니다.
public double squareRoot(double number);
구현을 작성했는지 또는 다른 사람이 작성했는지는 중요하지 않습니다. squareRoot의 몇 가지 속성을 지정하려고합니다.
따라서 이것을 개별 테스트로 작성하기 시작합니다.
@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?
}
시간이 지남에 따라 코드의 실제 작동 방식을 문서화하고 일종의 코드화 된 사양이되는 테스트 장치가 생깁니다. 레거시 코드를 변경하거나 다른 코드로 바꾸려면 테스트 코드를 사용하여 새 코드가 동일하게 동작하는지 또는 새 코드가 예상되고 제어 된 방식으로 다르게 동작하는지 (예 : 실제로 수정 될 것으로 예상되는 버그 수정). 이 하네스는 첫날에 완성 될 필요는 없지만, 불완전한 하네스를 갖는 것이 하네스를 전혀 갖지 않는 것보다 거의 항상 좋습니다. 하네스를 사용하면 클라이언트 코드를 더 쉽게 작성할 수 있으며, 무언가를 변경할 때 어떤 부분이 깨질 지, 결국에는 어디에서 부러 졌는지 알 수 있습니다.
양식에 필수 필드를 채우는 것처럼 단위 테스트를 작성해야한다는 사고 방식에서 벗어나야합니다. 그리고 빨간색 선을 녹색으로 만들기 위해 단위 테스트를 작성해서는 안됩니다. 단위 테스트는 적이 아니며 단위 테스트는 친구입니다.
테스트 사례 (프린터)를 작성할 때 각 작은 구성 요소를 생각하려고 시도합니다. 예를 들어, 스캐너가 어떤 명령을 사용하는지 (pjl printer-job-language에서) 모든 기능을 테스트하기 위해 작성할 수있는 것을 말하겠습니다. 이제는 어떻게해야할까요?
각 주요 구성 요소마다 그렇게하려고하지만 하드웨어가 아닌 소프트웨어와 관련하여 각 방법 / 기능을보고 경계를 확인하고 싶습니다.