내부 부품 테스트


14

클래스 / 모듈 / 패키지 등의 내부 / 개인 구성 요소를 어느 정도 테스트합니까? 그것들을 전혀 테스트하거나 외부 세계에 대한 인터페이스를 테스트합니까? 이러한 내부의 예는 개인용 메소드입니다.

예를 들어, 하나의 중앙 프로 시저에서 호출 된 여러 내부 프로 시저 (함수 / 방법)가 있는 순환 재귀 파서가 있다고 가정하십시오 . 외부 세계와의 유일한 인터페이스는 문자열을 가져와 구문 분석 된 정보를 반환하는 중앙 프로 시저입니다. 다른 프로시 저는 문자열의 다른 부분을 구문 분석하며 중앙 프로 시저 또는 다른 프로 시저에서 호출됩니다.

당연히 외부 인터페이스를 샘플 문자열로 호출하고 수동으로 구문 분석 된 출력과 비교하여 테스트해야합니다. 그러나 다른 절차는 어떻습니까? 하위 문자열을 올바르게 구문 분석하는지 확인하기 위해 개별적으로 테스트 하시겠습니까?

몇 가지 주장을 생각할 수 있습니다.

찬성 :

  1. 더 많은 테스트가 항상 더 좋으며 이는 코드 적용 범위를 높이는 데 도움이 될 수 있습니다
  2. 일부 내부 구성 요소는 외부 인터페이스에 입력을 제공하여 특정 입력을 제공하기가 어려울 수 있습니다 (예 : 에지 사례)
  3. 보다 명확한 테스트. 내부 구성 요소에 (고정 된) 버그가있는 경우 해당 구성 요소에 대한 테스트 사례를 통해 해당 특정 구성 요소에 버그가 있음을 알 수 있습니다

단점 :

  1. 리팩토링은 너무 고통스럽고 시간이 많이 걸립니다. 변경하려면 외부 인터페이스 사용자가 영향을받지 않더라도 단위 테스트를 다시 작성해야합니다.
  2. 일부 언어 및 테스트 프레임 워크에서는 허용되지 않습니다

당신의 의견은 무엇입니까?


답변:


8

사례 : "모듈"(일반적으로 공용 인터페이스를 가지고 있고 아마도 내부 부분이있는 것)에는 복잡하고 관련된 논리가있다. 모듈 인터페이스 만 테스트하는 것은 모듈의 내부 구조와 관련하여 일종의 통합 테스트가 될 것이므로 오류가 발견 된 경우 이러한 테스트는 실패를 담당하는 정확한 내부 부품 / 구성 요소를 현지화하지 않습니다.

해결 방법 : 복잡한 내부 부품을 모듈 자체로 바꾸고, 단위 테스트를 수행하고 (너무 복잡한 경우에는이 단계를 반복) 원래 모듈로 가져옵니다. 이제 쉽게 테스트 할 수있는 간단한 모듈 세트 (동작이 올바른지 확인하고 오류를 수정)를 모두 갖추 었습니다.

노트 :

  • "하위 모듈"이 더 이상 새로운 / 변경된 계약을 이행하기에 충분한 서비스를 제공하지 않는 한, 모듈의 계약을 변경할 때 모듈 (이전) "하위 모듈"의 테스트에서 아무것도 변경할 필요가 없습니다.

  • 불필요하게 공개되는 것은 없습니다. 즉, 모듈의 계약이 유지되고 캡슐화가 유지됩니다.

[최신 정보]

객체의 내부 인터페이스 (개인적으로 가져온 모듈 / 패키지가 아닌 멤버를 의미 함)를 객체의 공용 인터페이스를 통해 입력으로 공급하는 것이 어려운 경우 스마트 내부 로직을 테스트하려면 다음을 수행하십시오.

  • 실제로 내부에서 상태를 설정하고 원하는대로 동작을 테스트하는 내장 (internal)에 대한 친구 (C ++ 용어로) 또는 패키지 (Java) 액세스와 함께 몇 가지 테스트 코드가 있습니다.

    • 테스트를 위해 내부에 직접 액세스하는 동시에 캡슐화를 다시 중단하지는 않습니다. 테스트를 "블랙 박스"로 실행하고 릴리스 빌드에서 컴파일하면됩니다.

하고 목록 레이아웃은 조금 깨진 것 같다 (
mlvljr

1
좋은 대답입니다. .NET에서는 [assembly: InternalsVisibleTo("MyUnitTestAssembly")]속성을 사용하여 AssemblyInfo.cs내부를 테스트 할 수 있습니다 . 그래도 속임수처럼 느껴집니다.
아무도

@rmx 무언가가 필요한 모든 기준을 충족하면 실제 치트와 공통점이 있어도 속임수가 아닙니다. 그러나 모듈 간 / 모듈 내 액세스라는 주제는 현대의 주류 언어에서 실제로 약간 생각되고 있습니다.
mlvljr

2

FSM 기반 코드에 대한 접근 방식은 전통적으로 사용되는 방식과 약간 다릅니다. 하드웨어 테스트 (일반적으로 FSM)에 대해 여기 에 설명 된 것과 매우 유사합니다 .

요컨대, 특정 출력을 생성 할뿐만 아니라 특정 "나쁜"출력을 생성 할 때 실패의 구성 요소로 실패한 구성 요소를 식별 할 수있는 테스트 입력 시퀀스 (또는 테스트 입력 시퀀스 세트)를 작성합니다. 이 접근 방식은 확장 성이 뛰어나므로 테스트 디자인에 더 많은 시간을할수록 테스트 성능이 향상됩니다.

이러한 종류의 테스트는 "기능 테스트"에 더 가깝지만 구현에 약간의 영향을 줄 때마다 테스트를 변경할 필요가 없습니다.


2

글쎄-그것은 달려있다 :-). BDD (Behaviour Driven Development) 또는 ATDD (Acceptance Test Driven Development) 접근 방식을 따르는 경우 다양한 입력으로 철저하게 테스트하는 한 공용 인터페이스를 테스트하는 것이 좋습니다. 실제로 중요합니다.

그러나 해당 알고리즘의 일부가 특정 시간 프레임 내에서 또는 특정 bigO 곡선 (예 : nlogn)을 따라 실행되도록하려면 개별 부품을 테스트해야합니다. 어떤 사람들은 이것을 전통적인 TDD / Unit Test 접근법이라고 부릅니다.

모든 것과 마찬가지로 YMMV


1

기능적인 의미를 여러 부분으로 분할, 예를 들어 ParseQuotedString(), ParseExpression(), ParseStatement(), ParseFile()그들 모두 공개. 구문이 너무 많이 변경되어 관련성이 없어 질 가능성은 얼마나됩니까?


1
이 접근 방식은 캡슐화가 약해지고 인터페이스 사용 / 이해가 더 크고 어렵습니다.
sara
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.