저는 여러분 대부분이 자동화 된 테스트를 많이 작성하고 있으며 단위 테스트시 일반적인 함정에 부딪혔다 고 확신합니다.
내 질문은 미래의 문제를 피하기 위해 테스트 작성에 대한 행동 규칙을 따르나요? 더 구체적으로 말하면 , 좋은 단위 테스트 의 속성은 무엇입니까 ? 아니면 테스트를 어떻게 작성합니까?
언어에 구애받지 않는 제안이 권장됩니다.
답변
소스를 연결하는 것으로 시작하겠습니다 -JUnit을 사용하는 Java의 Pragmatic Unit Testing (C # -Nunit도 포함 된 버전도 있지만이 버전도 있습니다. 대부분의 경우 불가지론 적입니다. 권장 됨)
Good Tests는 A TRIP 이어야합니다 (약어가 충분히 끈적 거리지 않습니다. 책에 치트 시트가 인쇄되어있어이 문제가 올바른지 확인해야했습니다 ..)
- 자동 : 테스트 호출 및 PASS / FAIL 결과 확인이 자동으로 수행되어야합니다.
- 철저한 : 범위; 버그는 코드의 특정 지역을 중심으로 클러스터되는 경향이 있지만 모든 주요 경로와 시나리오를 테스트해야합니다. 테스트되지 않은 지역을 알아야하는 경우 도구를 사용합니다.
- 반복 : 시험은 동일한 결과 때마다 .. 모든 시간을 생산한다. 테스트는 제어 할 수없는 매개 변수에 의존해서는 안됩니다.
- 독립 : 매우 중요합니다.
- 테스트는 한 번에 한 가지만 테스트해야합니다 . 여러 주장은 모두 하나의 기능 / 동작을 테스트하는 한 괜찮습니다. 테스트가 실패하면 문제의 위치를 정확히 찾아 내야합니다.
- 테스트 는 서로 의존해서는 안됩니다 .-격리 됨. 테스트 실행 순서에 대한 가정이 없습니다. 설정 / 해체를 적절하게 사용하여 각 테스트 전에 ‘클린 슬레이트’를 확인하십시오.
-
전문가가 : 장기적으로 당신은 그러므로 테스트 코드에 대한 좋은 디자인의 동일한 표준에 따라 생산 한 많은 테스트 코드 (안 많은 경우)로해야합니다. 의도를 드러내는 이름, 중복 없음, 좋은 이름의 테스트 등을 가진 잘 팩터링 된 메서드 클래스
-
좋은 테스트도 빠르게 실행 됩니다. 실행하는 데 0.5 초 이상 걸리는 모든 테스트를 수행해야합니다. 테스트 스위트를 실행하는 데 시간이 오래 걸릴수록 실행 빈도가 줄어 듭니다. 더 많은 변경 사항이있을수록 개발자는 실행 사이에 몰래 들어 가려고합니다. 어떤 것이 깨지면 .. 어떤 변경이 원인인지 알아내는 데 시간이 더 오래 걸립니다.
2010-08 업데이트 :
- 가독성 : 이것은 Professional의 일부로 간주 될 수 있지만 충분히 강조 할 수는 없습니다. 산성 테스트는 팀의 일원이 아닌 사람을 찾아서 몇 분 안에 테스트중인 행동을 파악하도록 요청하는 것입니다. 테스트는 프로덕션 코드처럼 유지되어야하므로 더 많은 노력이 필요하더라도 쉽게 읽을 수 있도록해야합니다. 테스트는 대칭이어야하며 (패턴을 따름) 간결해야합니다 (한 번에 하나의 동작을 테스트). 일관된 명명 규칙 (예 : TestDox 스타일)을 사용합니다. “부수적 인 세부 사항”으로 테스트를 복잡하게 만들지 마십시오. 미니멀리스트가 되십시오.
이 외에도 대부분의 다른 것들은 저수익 작업을 줄이는 지침입니다. 예 : ‘소유하지 않는 코드는 테스트하지 마십시오'(예 : 타사 DLL). 게터와 세터를 테스트하지 마십시오. 비용 대 이익 비율 또는 결함 가능성을 주시하십시오.
답변
- 엄청난 테스트를 작성하지 마십시오. ‘단위 테스트’의 ‘단위’에서 알 수 있듯이 각 단위 를 가능한 한 원자 적 으로 분리 하십시오. 필요한 경우 일반적인 사용자 환경을 너무 많이 수동으로 다시 만드는 대신 모의 개체를 사용하여 전제 조건을 만듭니다.
- 분명히 작동하는 것을 테스트하지 마십시오. 타사 공급 업체의 클래스, 특히 코딩 한 프레임 워크의 핵심 API를 제공하는 공급 업체의 클래스를 테스트하지 마십시오. 예를 들어 공급 업체의 Hashtable 클래스에 항목을 추가하는 것을 테스트하지 마십시오.
- NCover와 같은 코드 커버리지 도구를 사용하여 아직 테스트하지 않은 엣지 케이스를 찾는 것을 고려하십시오 .
- 구현 하기 전에 테스트 를 작성하십시오 . 테스트를 구현이 준수 할 사양으로 생각하십시오. Cf. 또한 행동 중심 개발, 테스트 중심 개발의보다 구체적인 분기입니다.
- 일관성을 유지하십시오. 일부 코드에 대한 테스트 만 작성한다면 거의 유용하지 않습니다. 팀에서 일하고 다른 일부 또는 모두가 테스트를 작성하지 않으면 그다지 유용하지 않습니다. 자신과 다른 모든 사람에게 테스트 의 중요성 (및 시간 절약 속성)을 설득 하거나 귀찮게하지 마십시오.
답변
여기에있는 대부분의 답변은 실제로 테스트 자체 (어떻게)를 작성하는 것이 아니라 일반적으로 (언제, 어디서, 왜, 무엇을) 단위 테스트 모범 사례를 다루는 것 같습니다. 질문이 “어떻게”부분에 대해 매우 구체적으로 보였기 때문에, 나는 회사에서 실시한 “갈색 가방”프레젠테이션에서 가져온 이것을 게시 할 것이라고 생각했습니다.
Womp의 5 가지 작문 시험 법칙 :
1. 길고 설명적인 테스트 방법 이름을 사용합니다.
- Map_DefaultConstructorShouldCreateEmptyGisMap()
- ShouldAlwaysDelegateXMLCorrectlyToTheCustomHandlers()
- Dog_Object_Should_Eat_Homework_Object_When_Hungry()
2. Arrange / Act / Assert 스타일로 테스트를 작성합니다 .
- 이 조직 전략은 한동안 존재했고 많은 것을 불렀지 만, 최근에 “AAA”두문자어의 도입은이를 전달하는 좋은 방법이었습니다. 모든 테스트를 AAA 스타일과 일치 시키면 읽기 및 유지 관리가 쉽습니다.
3. 항상 어설 션과 함께 실패 메시지를 제공하십시오.
Assert.That(x == 2 && y == 2, "An incorrect number of begin/end element
processing events was raised by the XElementSerializer");
- 러너 애플리케이션에서 무엇이 실패했는지를 분명하게하는 간단하면서도 보람있는 연습입니다. 메시지를 제공하지 않으면 일반적으로 실패 출력에 “Expected true, was false”와 같은 메시지가 표시되므로 실제로 테스트를 읽어서 무엇이 잘못되었는지 확인해야합니다.
4. 테스트 이유를 설명하십시오 . 비즈니스 가정은 무엇입니까?
/// A layer cannot be constructed with a null gisLayer, as every function
/// in the Layer class assumes that a valid gisLayer is present.
[Test]
public void ShouldNotAllowConstructionWithANullGisLayer()
{
}
- 이것은 당연한 것처럼 보일 수 있지만이 방법은 처음에 테스트의 이유를 이해하지 못하는 사람들로부터 테스트의 무결성을 보호합니다. 나는 그 사람이 테스트가 검증하고 있다는 가정을 이해하지 못했기 때문에 완벽하게 괜찮은 많은 테스트가 제거되거나 수정되는 것을 보았습니다.
- 테스트가 사소하거나 메서드 이름이 충분히 설명적인 경우 주석을 생략 할 수 있습니다.
5. 모든 테스트는 항상 접촉하는 리소스의 상태를 되돌려 야합니다.
- 실제 자원을 다루지 않도록 가능한 경우 모의를 사용하십시오.
- 테스트 수준에서 정리를 수행해야합니다. 테스트는 실행 순서에 의존하지 않아야합니다.
답변
이러한 목표를 염두에 두십시오 (Meszaros의 xUnit Test Patterns 책에서 수정 됨).
- 테스트는 위험을 도입하는 것이 아니라 감소시켜야합니다.
- 테스트는 실행하기 쉬워야합니다.
- 테스트는 시스템이 주변에서 진화함에 따라 유지 관리가 쉬워야합니다.
더 쉽게 할 수있는 몇 가지 사항 :
- 테스트는 한 가지 이유 때문에 실패해야합니다.
- 테스트는 한 가지만 테스트해야합니다.
- 테스트 종속성 최소화 (데이터베이스, 파일, UI 등에 대한 종속성 없음)
당신도 당신의 xUnit의 프레임 워크 intergration 테스트를 할 수 있다는 것을 잊지 마세요 하지만 intergration 테스트 및 단위 테스트를 별도로 보관
답변
테스트는 격리되어야합니다. 한 테스트가 다른 테스트에 의존해서는 안됩니다. 더욱이 테스트는 외부 시스템에 의존해서는 안됩니다. 즉, 테스트 당신의 코드가 아닌 코드 코드는 on.You이 통합 또는 기능 테스트의 일환으로 그 상호 작용을 테스트 할 수 있습니다 따라 달라집니다.
답변
훌륭한 단위 테스트의 몇 가지 속성 :
-
테스트가 실패하면 문제가 어디에 있는지 즉시 알 수 있어야합니다. 디버거를 사용하여 문제를 추적해야하는 경우 테스트가 충분히 세분화되지 않은 것입니다. 테스트 당 단 하나의 주장 만 있으면 도움이됩니다.
-
리팩터링 할 때 테스트가 실패해서는 안됩니다.
-
테스트는 너무 빨리 실행되어 주저하지 않아야합니다.
-
모든 테스트는 항상 통과해야합니다. 비 결정적 결과가 없습니다.
-
단위 테스트는 프로덕션 코드와 마찬가지로 잘 구성되어야합니다.
@Alotor : 라이브러리에 외부 API에서만 단위 테스트가 있어야한다고 제안하는 경우 동의하지 않습니다. 외부 호출자에게 노출하지 않는 클래스를 포함하여 각 클래스에 대한 단위 테스트를 원합니다. (그러나 프라이빗 메서드에 대한 테스트를 작성해야한다고 생각되면 리팩토링해야합니다. )
편집 : “테스트 당 하나의 주장”으로 인한 중복에 대한 의견이있었습니다. 특히 시나리오를 설정하기위한 코드가 있고 이에 대해 여러 개의 어설 션을 만들고 싶지만 테스트 당 하나의 어설 션 만있는 경우 여러 테스트에서 설정을 복제 할 수 있습니다.
나는 그 접근 방식을 취하지 않습니다. 대신 시나리오별로 테스트 픽스처를 사용 합니다. 다음은 대략적인 예입니다.
[TestFixture]
public class StackTests
{
[TestFixture]
public class EmptyTests
{
Stack<int> _stack;
[TestSetup]
public void TestSetup()
{
_stack = new Stack<int>();
}
[TestMethod]
[ExpectedException (typeof(Exception))]
public void PopFails()
{
_stack.Pop();
}
[TestMethod]
public void IsEmpty()
{
Assert(_stack.IsEmpty());
}
}
[TestFixture]
public class PushedOneTests
{
Stack<int> _stack;
[TestSetup]
public void TestSetup()
{
_stack = new Stack<int>();
_stack.Push(7);
}
// Tests for one item on the stack...
}
}
답변
당신이 추구하는 것은 테스트중인 클래스의 행동을 묘사하는 것입니다.
- 예상되는 동작의 확인.
- 오류 사례 확인.
- 클래스 내의 모든 코드 경로를 포함합니다.
- 클래스 내의 모든 멤버 함수를 실행합니다.
기본적인 의도는 수업의 행동에 대한 자신감을 높이는 것입니다.
이는 코드를 리팩토링 할 때 특히 유용합니다. Martin Fowler는 그의 웹 사이트에서 테스트에 관한 흥미로운 기사 를 가지고 있습니다.
HTH.
건배,
Rob