모든 방법을 테스트해야합니까? 팀 테스트를

그래서 오늘 저는 팀 테스트를 통해 유닛 테스트에 대해 이야기했습니다. 그가 내게 물었을 때 모든 것이 시작되었습니다. “이봐 요, 그 수업의 시험은 어디에 있습니까?” 전체 클래스는 관리자 (또는 그렇게 부르기를 선호하는 경우 서비스)였으며 거의 ​​모든 메소드는 단순히 DAO에 물건을 위임했기 때문에 다음과 비슷했습니다.

SomeClass getSomething(parameters) {
    return myDao.findSomethingBySomething(parameters);
}

논리가없는 (또는 적어도 논리와 같은 단순한 위임을 고려하지는 않지만) 대부분의 경우 유용한 보일러 플레이트 (레이어 분리 등)는 상용구입니다. 그리고 우리는 그것을 단위 테스트해야하는지 아닌지에 대해 다소 긴 토론을했습니다 (DAO를 완전히 단위 테스트했다고 언급 할 가치가 있다고 생각합니다). 그의 주요 주장은 TDD가 아니었고 누군가 가이 방법이 무엇인지 확인하기 위해 테스트를보고 싶을 수도 있고 (더 분명한 방법을 모르겠습니다) 미래에 누군가가 구현하고 새로운 논리를 추가하십시오 (이 경우 누군가가 단순히 그 논리 를 테스트해야한다고 생각합니다 ).

그래도 그렇게 생각했습니다. 가장 높은 테스트 범위 %를 위해 노력해야합니까? 아니면 단순히 예술을위한 예술입니까? 나는 단순히 다음과 같은 것들을 테스트하는 이유를 보지 못합니다.

  • 게터와 세터 (실제로 논리가없는 한)
  • “boilerplate”코드

분명히 그러한 방법 (모의가있는)에 대한 테스트는 1 분도 걸리지 않지만 모든 CI에 대해 여전히 시간이 낭비되고 밀리 초가 더 걸린 것 같습니다.

모든 (또는 가능한 한 많은) 코드 라인을 테스트해야하는 합리적 / 가연성 이유가 있습니까?



답변

나는 켄트 벡 (Kent Beck)의 경험에 따라 간다 :

파손될 수있는 모든 것을 시험하십시오.

물론, 그것은 어느 정도 주관적입니다. 나에게, 위와 같은 사소한 게터 / 세터와 원 라이너는 그만한 가치가 없다. 그러나 다시 한 번, 대부분의 시간을 레거시 코드에 대한 단위 테스트를 작성하면서 멋진 그린 필드 TDD 프로젝트를 꿈꾸고 있습니다 … 그러한 프로젝트에서는 규칙이 다릅니다. 레거시 코드를 사용하는 경우 주된 목표는 가능한 적은 노력으로 최대한 많은 근거를 다루는 것이므로 단위 테스트는 용어에 대한 지식이있는 경우 통합 테스트와 같이 더 높은 수준과 더 복잡한 경향이 있습니다. 그리고 전체 코드 범위를 0 %에서 올리려고 애 쓰고 있거나 25 % 이상 부딪 칠 때 단위 테스트 게터와 세터는 걱정할 필요가 없습니다.

그린 필드 TDD 프로젝트에서 OTOH의 경우 이러한 방법에 대한 테스트도 작성하는 것이 더 중요 할 수 있습니다. 특히 이미 테스트를 작성 했으므로 “이 한 줄은 전용 테스트의 가치가 있습니까?” 그리고 최소한 이러한 테스트는 작성하기가 쉽고 실행 속도가 빠르므로 큰 문제는 아닙니다.


답변

단위 테스트에는 몇 가지 유형이 있습니다.

  • 상태 기반. 당신은 행동하고 물체의 상태에 대해 주장한다. 예를 들어 예금을합니다. 그런 다음 잔액이 증가했는지 확인합니다.
  • 반환 값을 기준으로합니다. 귀하는 반품 가치에 대해 행동하고 주장합니다.
  • 상호 작용 기반. 객체가 다른 객체를 호출했는지 확인합니다. 이것은 당신이 당신의 모범에서하고있는 것처럼 보입니다.

테스트를 먼저 작성했다면 데이터 액세스 계층을 호출 할 것으로 예상되는 것보다 더 의미가 있습니다. 처음에는 테스트가 실패합니다. 그런 다음 테스트를 통과하기 위해 프로덕션 코드를 작성합니다.

이상적으로는 논리 코드를 테스트해야하지만 상호 작용 (다른 개체를 호출하는 개체)도 마찬가지로 중요합니다. 네 경우에는

  • 전달 된 정확한 매개 변수를 사용하여 데이터 액세스 계층을 호출했는지 확인하십시오.
  • 한 번만 호출되었는지 확인하십시오.
  • 데이터 액세스 계층에서받은 내용을 정확하게 반환하는지 확인하십시오. 그렇지 않으면 null을 반환 할 수도 있습니다.

현재 거기에는 논리가 없지만 항상 그런 것은 아닙니다.

그러나이 방법에 논리가 없으며 그것이 동일하게 유지 될 것이라고 확신한다면 소비자로부터 직접 데이터 액세스 계층을 호출하는 것을 고려할 것입니다. 나머지 팀이 같은 페이지에있는 경우에만이 작업을 수행합니다. “이봐, 도메인 레이어를 무시하고 데이터 액세스 레이어를 직접 호출하는 것이 좋습니다”라고 말하여 팀에 잘못된 메시지를 보내지 않으려 고합니다.

이 방법에 대한 통합 테스트가 있다면 다른 구성 요소 테스트에도 집중할 것입니다. 그래도 견고한 통합 테스트를 한 회사는 아직 보지 못했습니다.

이 모든 것을 말하면서-나는 모든 것을 맹목적으로 테스트하지는 않을 것입니다. 핫스팟 (높은 복잡성과 높은 파괴 위험을 가진 구성 요소)을 설정합니다. 그런 다음 이러한 구성 요소에 집중합니다. 나머지 90 %가 시스템의 핵심 로직을 나타내며 복잡성으로 인해 단위 테스트에 포함되지 않는 경우 코드베이스의 90 %가 매우 간단하고 단위 테스트에 의해 다루어지는 코드베이스를 가질 필요는 없습니다.

마지막으로이 방법을 테스트하면 어떤 이점이 있습니까? 이것이 작동하지 않으면 어떤 의미가 있습니까? 그들은 치명적인가? 높은 코드 적용 범위를 얻으려고 노력하지 마십시오. 코드 범위는 우수한 단위 테스트 제품군의 제품이어야합니다. 예를 들어, 트리를 따라 이동하여이 방법의 100 % 적용 범위를 제공하는 하나의 테스트를 작성하거나 100 % 적용 범위를 제공하는 3 가지 단위 테스트를 작성할 수 있습니다. 차이점은 세 가지 테스트를 작성하여 트리를 걷는 것과는 대조적으로 에지 사례를 테스트한다는 것입니다.


답변

소프트웨어의 품질을 생각하는 좋은 방법은 다음과 같습니다.

  1. 유형 검사는 문제의 일부를 처리합니다.
  2. 테스트는 나머지를 처리합니다

상용구 및 사소한 기능의 경우 작업을 수행하는 유형 검사에 의존 할 수 있으며 나머지는 테스트 사례가 필요합니다.


답변

제 생각에는 순환 복잡성은 매개 변수입니다. 메소드가 충분히 복잡하지 않은 경우 (예 : 게터 및 세터). 단위 테스트가 필요하지 않습니다. McCabe의 Cyclomatic Complexity 수준은 1보다 커야합니다. 또 다른 단어는 최소 1 개의 블록 설명이 있어야합니다.


답변

TDD와 함께 그렇습니다 (몇 가지 예외가 있음)

논란의 여지가 있지만, 나는이 질문에 ‘아니오’라고 대답하는 사람은 TDD의 기본 개념이 누락되었다고 주장합니다.

나를 위해, 대답은 울려 퍼지는이다 는 TDD를 수행합니다. 그렇지 않다면 그럴듯한 대답은 없습니다.

TDD의 DDD

TDD는 종종 주요 이점이 있다고 인용됩니다.

  • 방어
    • 코드가 변경 될 수 있지만 동작 은 변경 되지 않는지 확인하십시오 .
    • 이것은 리팩토링의 매우 중요한 관행을 허용합니다 .
    • 이 TDD를 얻거나 얻지 못합니다.
  • 디자인
    • 당신은 지정 이 작동하는 방법, 뭔가해야 할 일 구현하기 전에 그것을.
    • 이것은 종종보다 현명한 구현 결정을 의미 합니다.
  • 문서
    • 테스트 스위트는 사양 (요구 사항) 문서 로 사용되어야합니다 .
    • 그러한 목적으로 테스트를 사용한다는 것은 문서와 구현이 항상 일관된 상태임을 의미합니다. 하나의 변경은 다른 변경을 의미합니다. 별도의 워드 문서에서 요구 사항과 디자인을 유지하는 것과 비교하십시오.

구현과 별도의 책임

프로그래머로서, 속성을 중요하고 게터로 생각하고 일종의 오버 헤드로 세터를 생각하는 것은 대단히 유혹적입니다.

그러나 속성은 구현 세부 사항이며 세터와 게터는 실제로 프로그램을 작동시키는 계약 인터페이스입니다.

객체가 다음과 같이 철자를 작성하는 것이 훨씬 더 중요합니다.

클라이언트가 상태를 변경하도록 허용

클라이언트가 상태를 쿼리하도록 허용

그런 다음이 상태가 실제로 저장되는 방법 (속성이 가장 일반적이지만 유일한 방법은 아닙니다).

다음과 같은 테스트

(The Painter class) should store the provided colour

TDD 의 문서 부분에 중요합니다 .

테스트를 작성할 때 최종 구현이 사소한 (속성) 방어 이점 이 없다는 사실을 알 수 없습니다.

왕복 공학의 부족 …

시스템 개발 세계의 주요 문제 중 하나는 왕복 공학 의 부족입니다. 1- 시스템의 개발 프로세스가 분리 된 하위 프로세스로 분할됩니다 (문서, 코드).

1 Brodie, Michael L. “John Mylopoulos : 개념적 모델링의 씨앗 봉제.” 개념 모델링 : 기초 및 응용. Springer Berlin Heidelberg, 2009. 1-9.

… 그리고 TDD가이를 해결하는 방법

시스템 및 해당 코드의 스펙이 항상 일관되도록 TDD 의 문서 부분입니다.

먼저 디자인하고 나중에 구현

TDD 내에서 먼저 합격 합격 테스트를 작성한 다음 통과시키는 코드 만 작성하십시오.

높은 수준의 BDD 내에서 시나리오를 먼저 작성한 다음 통과시킵니다.

왜 세터와 게터를 제외해야합니까?

이론적으로 TDD 내에서 한 사람이 테스트를 작성하고 다른 사람이 테스트를 통과시키는 코드를 구현할 수 있습니다.

스스로에게 물어보십시오.

클래스에 대한 테스트를 작성하는 사람이 getter 및 setter를 언급해야합니다.

getter와 setter는 클래스에 대한 공용 인터페이스이므로 대답은 명백히 yes 이거나 객체의 상태를 설정하거나 쿼리 할 방법이 없습니다.

분명히 코드를 먼저 작성하면 답이 명확하지 않을 수 있습니다.

예외

이 규칙에는 명백한 구현 세부 사항이며 시스템 설계의 일부가 아닌 기능인 몇 가지 명백한 예외가 있습니다.

예를 들어 로컬 메소드 ‘B ()’:

function A() {

    // B() will be called here

    function B() {
        ...
    }
}

또는 square()여기 개인 기능 :

class Something {
private:
    square() {...}
public:
    addAndSquare() {...}
    substractAndSquare() {...}
}

또는 public시스템 구성 요소 설계에서 철자를 필요 로하는 인터페이스의 일부가 아닌 다른 기능 .


답변

철학적 quesion에 직면하면 운전 요구 사항으로 돌아갑니다.

합리적인 비용으로 합리적으로 신뢰할 수있는 소프트웨어를 생산하는 것이 목표입니까?

아니면 거의 비용에 관계없이 최고의 신뢰성을 가진 소프트웨어를 생산하는 것입니까?

요컨대, 품질과 개발 속도 / 비용의 두 가지 목표는 결함을 수정하는 것보다 테스트를 작성하는 데 더 적은 시간을 소비한다는 것입니다.

그러나 그 시점을 넘어서는 그렇지 않습니다. 예를 들어 한 달에 한 개발자 당 버그가보고 된 것은 그리 어렵지 않습니다. 이를 2 개월에 1 개로 줄이면 하루나 이틀 정도의 예산 만 책정되며 추가 테스트를 통해 결함률을 절반으로 줄일 수는 없습니다. 따라서 더 이상 단순한 승리 / 승리가 아닙니다. 고객의 결함 비용을 기준으로이를 정당화해야합니다.

이 비용은 다양 할 것입니다 (그리고 당신이 악하기를 원한다면 시장이나 소송을 통해 그 비용을 당신에게 다시 집행 할 수있는 능력). 당신은 악하기를 원하지 않기 때문에 그 비용을 모두 다시 계산합니다. 때로는 일부 테스트가 여전히 전 세계적으로 존재하기 때문에 세상을 더 나쁘게 만듭니다.

요컨대, 여객 정기 여객기 비행 소프트웨어와 동일한 표준을 사내 웹 사이트에 맹목적으로 적용하려고하면 사업이 중단되거나 투옥 될 수 있습니다.


답변

이것에 대한 당신의 대답은 당신의 철학에 달려 있습니다 (시카고 대 런던이라고 믿습니까? 누군가 그것을 찾을 것이라고 확신합니다). 배심원은 여전히 ​​가장 시간 효율적인 접근 방식으로이 문제를 해결하지 못하고 있습니다.

어떤 접근법은 공용 인터페이스 만 테스트한다고 말하고 다른 접근법은 모든 함수에서 각 함수 호출의 순서를 테스트한다고 말합니다. 많은 거룩한 전쟁이 벌어졌습니다. 내 충고는 두 가지 접근법을 모두 시도하는 것입니다. 코드 단위를 선택하고 X, Y와 같은 코드를 선택하십시오. 몇 개월의 테스트 및 통합 후 돌아가서 어느 것이 더 적합한 지 확인하십시오.