서브 클래스 또는 추상 부모 클래스를 단위 테스트해야합니까?


12

나는 효과적인 자바 (확장 토론에서 항목 18로, 스켈 리턴 구현을 여기 ). 추상 클래스로는 정의 할 수없는 "갭을 메우기"위해 서브 클래스 메소드를 호출하는 2 개의 공용 메소드 methodA () 및 methodB ()를 제공하는 추상 클래스입니다.

먼저 구체적인 클래스를 만들고 단위 테스트를 작성하여 개발했습니다. 두 번째 클래스가 왔을 때, 나는 일반적인 행동을 추출하고 두 번째 클래스에서 "누락 간격"을 구현할 수 있었고 준비가되었습니다 (물론 두 번째 하위 클래스에 대한 단위 테스트가 만들어졌습니다).

시간이 흐르면서 지금은 4 개의 서브 클래스가 있는데, 각 서브 클래스는 구체적인 구현에 매우 특정한 3 개의 짧은 보호 된 메소드를 구현하는 반면 골격 구현은 모든 일반 작업을 수행합니다.

내 문제는 새로운 구현을 만들 때 테스트를 다시 작성한다는 것입니다.

  • 서브 클래스는 주어진 필수 메소드를 호출합니까?
  • 주어진 메소드에 주어진 주석이 있습니까?
  • 방법 A에서 예상되는 결과를 얻습니까?
  • 방법 B에서 예상되는 결과를 얻습니까?

이 접근 방식의 장점을 참조하십시오.

  • 테스트를 통해 서브 클래스 요구 사항을 문서화합니다.
  • 리팩토링에 문제가있는 경우 빠르게 실패 할 수 있습니다
  • 서브 클래스를 전체적으로 그리고 공용 API를 통해 테스트하십시오 ( "methodA ()가 작동합니까?"및 "이 보호 된 메소드가 작동합니까?").

내가 가지고있는 문제는 새로운 서브 클래스에 대한 테스트가 기본적으로 쉬운 일이 없다는 것입니다. 테스트의 어설 션 부분을 확인하십시오. -일반적으로 서브 클래스에는 특정 테스트가 없습니다.

테스트가 서브 클래스 자체의 결과에 중점을두고 리팩토링으로부터 보호하는 방식이 마음에 들지만 테스트 구현이 "수동 작업"이되었다는 사실로 인해 내가 뭔가 잘못하고 있다고 생각합니다.

클래스 계층을 테스트 할 때이 문제가 일반적입니까? 어떻게 피할 수 있습니까?

추신 : 나는 골격 클래스를 테스트하는 것에 대해 생각했지만 테스트 할 수있는 추상 클래스의 모형을 만드는 것이 이상하게 보입니다. 그리고 서브 클래스에서 예상하지 않은 동작을 변경하는 추상 클래스의 리팩토링은 빠르지 않을 것이라고 생각합니다. 내 직감은 서브 클래스를 "전체적으로"테스트하는 것이 여기에서 선호되는 접근법이라고 말하지만, 내가 틀렸다고 말해주십시오. :)

추신 : 나는 구글과 주제에 관한 많은 질문을 발견했습니다. 그 중 하나는 이쪽좋은 답변을 내 경우는 자신의 '숫자 1'이 될 것입니다, 나이젤 쏜에서을 그것은 좋을 것이지만, 지금은 리팩터링 할 수 없으므로이 문제로 살아야합니다. 리팩토링 할 수 있으면 각 하위 클래스를 전략으로 사용합니다. 괜찮지 만, 여전히 "주요 클래스"를 테스트하고 전략을 테스트 하겠지만 주 클래스와 전략의 통합을 방해하는 리팩터링은 눈치 채지 못할 것입니다.

추신 : 추상 클래스를 테스트하는 것이 "허용됩니다"라는 답변을 찾았습니다. 나는 이것이 수용 가능하다는 것에 동의하지만,이 경우 어떤 접근법이 선호되는지 알고 싶습니다. (여전히 단위 테스트로 시작하고 있습니다)


2
추상 테스트 클래스를 작성하고 구체적인 테스트 클래스를 상속하여 비즈니스 코드의 구조를 반영하십시오. 테스트는 유닛의 구현이 아닌 동작을 테스트하는 것으로 가정하지만, 시스템에 대한 내부 지식을 사용하여 해당 목표를보다 효율적으로 달성 할 수는 없습니다.
Kilian Foth

테스트에서 상속을 사용해서는 안되는 곳을 읽었습니다. 소스를주의 깊게 읽을 소스를 찾고 있습니다.
JSBach

4
@KilianFoth이 조언에 대해 확신하십니까? 이는 취성 단위 테스트를위한 레시피처럼 들리며 설계 변경에 매우 민감하므로 유지 관리가 쉽지 않습니다.
Konrad Morawski

답변:


5

추상 기본 클래스에 대한 테스트를 작성하는 방법을 알 수 없습니다 . 당신이 그것의 인스턴스를 가질 수 없습니다, 그래서 당신은 그것을 인스턴스화 할 수 없습니다 테스트. 테스트 목적으로 만 "더미", 구체적 서브 클래스를 작성할 수 있습니다. YMMV.

새로운 구현 (클래스)을 만들 때마다 새로운 구현을 수행하는 테스트를 작성해야합니다. 기능의 일부 ( "갭")는 서브 클래스 내에 구현 되므로 반드시 필요합니다. 상속 된 방법의 각각의 출력은 (아마도있다 한다 ) 각각의 새로운 구현 달라도.


그렇습니다. 유형과 내용이 다릅니다. 기술적으로 말하면,이 클래스를 조롱하거나 빈 구현으로 테스트 목적으로 만 간단한 구현을 할 수 있습니다. 나는이 접근법을 좋아하지 않는다. 그러나 새로운 구현에서 테스트를 통과해야한다고 생각할 필요가 없다는 사실은 내가 이상하게 느끼고이 테스트에 얼마나 자신감이 있는지에 대한 질문을합니다 (물론 기본 클래스를 의도적으로 변경하면 테스트 실패, 이는 내가 믿을 수 있다는 증거입니다)
JSBach

4

일반적으로 인터페이스를 적용 할 기본 클래스를 작성합니다. 아래 세부 정보가 아닌 해당 인터페이스를 테스트하려고합니다. 따라서 각 클래스를 개별적으로 인스턴스화하지만 기본 클래스의 메소드를 통해서만 테스트하는 테스트를 작성해야합니다.

이 방법의 장점은 인터페이스를 테스트 했으므로 이제 인터페이스 아래에서 리팩토링 할 수 있다는 것입니다. 자식 클래스의 코드가 부모 클래스에 있거나 그 반대 인 것을 알 수 있습니다. 이제 테스트를 통해 해당 코드를 이동할 때 동작이 중단되지 않았 음을 확인할 수 있습니다.

일반적으로 코드의 사용법을 테스트해야합니다. 즉, 비공개 메소드 테스트를 피해야하며 테스트중인 단위가 원래 생각했던 것보다 약간 클 수도 있습니다 (아마도 단일 클래스가 아닌 클래스 그룹 일 수 있음) . 주어진 범위에서 리팩토링 할 때 테스트를 거의 변경하지 않도록 변경 사항을 분리하는 것이 목표입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.