[unit-testing] 좋은 단위 테스트는 무엇입니까? [닫은]

저는 여러분 대부분이 자동화 된 테스트를 많이 작성하고 있으며 단위 테스트시 일반적인 함정에 부딪혔다 고 확신합니다.

내 질문은 미래의 문제를 피하기 위해 테스트 작성에 대한 행동 규칙을 따르나요? 더 구체적으로 말하면 , 좋은 단위 테스트속성은 무엇입니까 ? 아니면 테스트를 어떻게 작성합니까?

언어에 구애받지 않는 제안이 권장됩니다.



답변

소스를 연결하는 것으로 시작하겠습니다 -JUnit을 사용하는 Java의 Pragmatic Unit Testing (C # -Nunit도 포함 된 버전도 있지만이 버전도 있습니다. 대부분의 경우 불가지론 적입니다. 권장 됨)

Good Tests는 A TRIP 이어야합니다 (약어가 충분히 끈적 거리지 않습니다. 책에 치트 시트가 인쇄되어있어이 문제가 올바른지 확인해야했습니다 ..)

  • 자동 : 테스트 호출 및 PASS / FAIL 결과 확인이 자동으로 수행되어야합니다.
  • 철저한 : 범위; 버그는 코드의 특정 지역을 중심으로 클러스터되는 경향이 있지만 모든 주요 경로와 시나리오를 테스트해야합니다. 테스트되지 않은 지역을 알아야하는 경우 도구를 사용합니다.
  • 반복 : 시험은 동일한 결과 때마다 .. 모든 시간을 생산한다. 테스트는 제어 할 수없는 매개 변수에 의존해서는 안됩니다.
  • 독립 : 매우 중요합니다.
    • 테스트는 한 번에 한 가지만 테스트해야합니다 . 여러 주장은 모두 하나의 기능 / 동작을 테스트하는 한 괜찮습니다. 테스트가 실패하면 문제의 위치를 ​​정확히 찾아 내야합니다.
    • 테스트 는 서로 의존해서는 안됩니다 .-격리 됨. 테스트 실행 순서에 대한 가정이 없습니다. 설정 / 해체를 적절하게 사용하여 각 테스트 전에 ‘클린 슬레이트’를 확인하십시오.
  • 전문가가 : 장기적으로 당신은 그러므로 테스트 코드에 대한 좋은 디자인의 동일한 표준에 따라 생산 한 많은 테스트 코드 (안 많은 경우)로해야합니다. 의도를 드러내는 이름, 중복 없음, 좋은 이름의 테스트 등을 가진 잘 팩터링 된 메서드 클래스

  • 좋은 테스트도 빠르게 실행 됩니다. 실행하는 데 0.5 초 이상 걸리는 모든 테스트를 수행해야합니다. 테스트 스위트를 실행하는 데 시간이 오래 걸릴수록 실행 빈도가 줄어 듭니다. 더 많은 변경 사항이있을수록 개발자는 실행 사이에 몰래 들어 가려고합니다. 어떤 것이 깨지면 .. 어떤 변경이 원인인지 알아내는 데 시간이 더 오래 걸립니다.

2010-08 업데이트 :

  • 가독성 : 이것은 Professional의 일부로 간주 될 수 있지만 충분히 강조 할 수는 없습니다. 산성 테스트는 팀의 일원이 아닌 사람을 찾아서 몇 분 안에 테스트중인 행동을 파악하도록 요청하는 것입니다. 테스트는 프로덕션 코드처럼 유지되어야하므로 더 많은 노력이 필요하더라도 쉽게 읽을 수 있도록해야합니다. 테스트는 대칭이어야하며 (패턴을 따름) 간결해야합니다 (한 번에 하나의 동작을 테스트). 일관된 명명 규칙 (예 : TestDox 스타일)을 사용합니다. “부수적 인 세부 사항”으로 테스트를 복잡하게 만들지 마십시오. 미니멀리스트가 되십시오.

이 외에도 대부분의 다른 것들은 저수익 작업을 줄이는 지침입니다. 예 : ‘소유하지 않는 코드는 테스트하지 마십시오'(예 : 타사 DLL). 게터와 세터를 테스트하지 마십시오. 비용 대 이익 비율 또는 결함 가능성을 주시하십시오.


답변

  1. 엄청난 테스트를 작성하지 마십시오. ‘단위 테스트’의 ‘단위’에서 알 수 있듯이 각 단위 를 가능한 한 원자 적 으로 분리 하십시오. 필요한 경우 일반적인 사용자 환경을 너무 많이 수동으로 다시 만드는 대신 모의 개체를 사용하여 전제 조건을 만듭니다.
  2. 분명히 작동하는 것을 테스트하지 마십시오. 타사 공급 업체의 클래스, 특히 코딩 한 프레임 워크의 핵심 API를 제공하는 공급 업체의 클래스를 테스트하지 마십시오. 예를 들어 공급 업체의 Hashtable 클래스에 항목을 추가하는 것을 테스트하지 마십시오.
  3. NCover와 같은 코드 커버리지 도구를 사용하여 아직 테스트하지 않은 엣지 케이스를 찾는 것을 고려하십시오 .
  4. 구현 하기 전에 테스트 작성하십시오 . 테스트를 구현이 준수 할 사양으로 생각하십시오. Cf. 또한 행동 중심 개발, 테스트 중심 개발의보다 구체적인 분기입니다.
  5. 일관성을 유지하십시오. 일부 코드에 대한 테스트 만 작성한다면 거의 유용하지 않습니다. 팀에서 일하고 다른 일부 또는 모두가 테스트를 작성하지 않으면 그다지 유용하지 않습니다. 자신과 다른 모든 사람에게 테스트 의 중요성 (및 시간 절약 속성)을 설득 하거나 귀찮게하지 마십시오.

답변

여기에있는 대부분의 답변은 실제로 테스트 자체 (어떻게)를 작성하는 것이 아니라 일반적으로 (언제, 어디서, 왜, 무엇을) 단위 테스트 모범 사례를 다루는 것 같습니다. 질문이 “어떻게”부분에 대해 매우 구체적으로 보였기 때문에, 나는 회사에서 실시한 “갈색 가방”프레젠테이션에서 가져온 이것을 게시 할 것이라고 생각했습니다.

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...
    }
}


답변

당신이 추구하는 것은 테스트중인 클래스의 행동을 묘사하는 것입니다.

  1. 예상되는 동작의 확인.
  2. 오류 사례 확인.
  3. 클래스 내의 모든 코드 경로를 포함합니다.
  4. 클래스 내의 모든 멤버 함수를 실행합니다.

기본적인 의도는 수업의 행동에 대한 자신감을 높이는 것입니다.

이는 코드를 리팩토링 할 때 특히 유용합니다. Martin Fowler는 그의 웹 사이트에서 테스트에 관한 흥미로운 기사 를 가지고 있습니다.

HTH.

건배,

Rob