개인 메소드를 단위 테스트 할 필요가없는 방법


15

나는 당신이 개인 메소드를 테스트하지 않아야한다는 것을 알고 있습니다. 필요한 것처럼 보이면 클래스가 나올 수 있습니다.

그러나 공용 인터페이스를 테스트 할 수 있도록 gazillion 클래스를 원하지 않고 공개 클래스를 테스트하면 많은 클래스에서 많은 의존성을 조롱해야하며 단위 테스트는 다음과 같습니다. 엄청나고 따르기가 어렵다.

공개 메소드를 테스트 할 때 개인 메소드를 조롱하고 비공개 메소드를 테스트 할 때 외부 종속성을 조롱하는 것을 선호합니다.

내가 미쳤어?


철저한 단위 테스트는 주어진 클래스의 모든 개인 멤버를 암시 적으로 다루어야합니다. 직접 호출 할 수는 없지만 그들의 행동은 여전히 ​​출력에 영향을 미치기 때문입니다. 그렇지 않다면 왜 처음에 있습니까? 단위 테스트에서 결과가 어떻게 도달했는지가 아니라 결과가 중요하다는 것을 기억하십시오.
GordonM

답변:


24

당신은 부분적으로 옳습니다- 개인 메소드를 직접 테스트 해서는 안됩니다 . 클래스의 개인 메소드는 하나 이상의 공개 메소드에 의해 호출되어야합니다 (아마도 간접적으로-공개 메소드에 의해 호출 된 개인 메소드는 다른 개인 메소드를 호출 할 수 있습니다). 따라서 공개 메소드를 테스트 할 때 개인 메소드도 테스트합니다. 테스트되지 않은 개인 메소드가있는 경우 테스트 케이스가 충분하지 않거나 개인 메소드가 사용되지 않아 제거 할 수 있습니다.

화이트 박스 테스트 방식을 사용하는 경우 공개 메소드를 중심으로 단위 테스트를 구성 할 때 개인 메소드의 구현 세부 사항을 고려해야합니다. 블랙 박스 접근 방식을 사용하는 경우 공개 또는 개인 메소드의 구현 세부 사항을 기준으로 테스트하지 말고 예상되는 동작을 테스트해야합니다.

개인적으로, 나는 단위 테스트에 화이트 박스 접근법을 선호합니다. 테스트 할 메소드와 클래스를 다른 상태로 설정하여 공개 및 개인 메소드에서 흥미로운 동작을 유발 한 다음 결과가 내가 기대하는 것이라고 주장 할 수있는 테스트를 만들 수 있습니다.

따라서 개인 방법을 조롱하지 마십시오. 사용자가 제공하는 기능을 제대로 다루기 위해 테스트해야 할 내용을 이해하는 데 사용하십시오. 이것은 단위 테스트 수준에서 특히 그렇습니다.


1
"개인적인 방법을 조롱하지 마라"네, 테스팅을 이해할 수 있습니다. 조롱 할 때 미세한 선을 넘어 미쳐 버릴 수도 있습니다
Ewan

그래도 내가 말했듯이, 화이트 박스 테스트의 문제점은 일반적으로 공개 및 개인 메소드에 대한 모든 종속성을 조롱하면 실제로 큰 테스트 메소드를 만드는 것입니다. 어떻게 해결할 수 있습니까?
Fran Sevillano

8
@FranSevillano 당신이 그렇게 많이 스터브하거나 조롱해야한다면, 나는 당신의 전반적인 디자인을 볼 것입니다. 기분이 상쾌합니다.
토마스 오웬스

코드 적용 툴이이를 도와줍니다.
Andy

5
@FranSevillano : 클래스가 수많은 의존성을 가지도록하는 좋은 이유는 많지 않습니다. 당신이 많은 의존성을 가지고 있다면 아마도 신 클래스가있을 것입니다.
Mooing Duck

4

나는 이것이 매우 나쁜 생각이라고 생각합니다.

개인 구성원의 단위 테스트 작성시 문제점은 제품 수명주기에 적합하지 않다는 것입니다.

이러한 메소드를 비공개로 설정 한 이유는 클래스가 수행하려는 작업의 중심이 아니기 때문에 현재 해당 기능을 구현하는 방법을 돕는 도우미이기 때문입니다. 리팩토링 할 때 이러한 개인 정보는 변경 될 수 있으며 리팩토링과 마찰을 일으킬 수 있습니다.

또한 공개 및 개인 구성원의 주요 차이점은 공개 API를 신중하게 생각하고 잘 문서화하고 잘 확인해야한다는 것입니다 (어설 션 등). 그러나 개인 API를 사용하면 신중하게 생각하는 것이 의미가 없습니다 (사용이 너무 현지화되어 있기 때문에 낭비되는 노력). 개인 메소드를 단위 테스트에 넣으면 해당 메소드에 대한 외부 종속성을 작성해야합니다. 의미는 API가 안정적이고 잘 문서화되어야 함을 의미합니다 (누군가가 왜 그렇게 할 때 단위 테스트가 실패했는지 파악해야하기 때문에).

나는 너에게 제안한다:

  • 해당 메소드가 개인용이어야하는지 재검토하십시오
  • 일회성 테스트 작성 (지금 정확한지 확인하고 일시적으로 공개하여 테스트 한 다음 삭제)
  • #ifdef 및 어설 션을 사용하여 구현에 조건부 테스트를 빌드했습니다 (테스트는 디버그 빌드에서만 수행됨).

이 기능을 테스트하려는 성향과 현재 공개 API를 통해 테스트하기가 어렵다는 것에 감사드립니다. 그러나 저는 개인적으로 테스트 범위보다 모듈성을 중요하게 생각합니다.


6
동의하지 않습니다. IMO는 통합 테스트에 100 % 정확합니다. 그러나 단위 테스트에서는 상황이 다릅니다. 단위 테스트의 목표는 버그가있는 곳을 정확히 찾아 내서 신속하게 수정할 수 있도록하는 것입니다. 나는이 상황에서 나 자신을 자주 발견합니다. 공개 방법은 거의 없습니다. 왜냐하면 그것이 클래스의 핵심 가치이기 때문입니다 (당신이 말한 것처럼). 그러나 나는 또한 공개 또는 비공개가 아닌 400 개의 라인 메소드를 작성하지 않습니다. 따라서 몇 가지 공개 방법은 수십 가지 개인 방법을 통해서만 목표를 달성 할 수 있습니다. "빠른 해결"코드가 너무 많습니다. 디버거 등을 시작해야합니다.
marstato

6
@marstato : 제안 : 먼저 테스트 작성을 시작하고 단위 테스트에 대한 생각을 바꾸십시오. 버그를 찾지는 않지만 코드가 개발자가 의도 한대로 작동하는지 확인하십시오.
Timothy Truckle

@marstato 감사합니다! 예. 물건을 체크인 할 때 (또는 체크인하지 않았을 때) 테스트는 항상 처음으로 통과합니다. 그것들은 코드를 발전시킬 때 유용하며, 무언가를 깨뜨릴 때 머리를 숙이고, 좋은 회귀 테스트가 있으면 문제를 찾을 위치에 대한 COMFORT / GUIDANCE를 제공합니다 (안정적인 것은 아닙니다) 잘 회귀 테스트).
루이스 프링 글

@marstato "단위 테스트의 목표는 버그가있는 곳을 찾아내는 것입니다."-OP의 질문으로 이어지는 오해입니다. 단위 테스트의 목표는 API의 의도 된 (그리고 바람직하게 문서화 된) 동작을 확인하는 것입니다.
StackOverthrow

4
@marstato 이름 "통합 테스트"는 여러 구성 요소가 함께 작동하는지 테스트합니다 (즉, 올바르게 통합). 단위 테스트는 단일 구성 요소를 테스트하는 것이 개별적으로 수행 해야하는 작업을 수행한다는 것입니다. 이는 기본적으로 공개 API가 문서화 / 요구대로 작동한다는 것을 의미합니다. 나도 그 용어를 사용하면 내부 구현 로직의 테스트를 포함 여부에 대해 아무것도 말하지 않는다 부분 통합이 작동하거나 하나의 단위가 작동한다는 것을 보장합니다.
Ben

3

UnitTests는 코드가 아닌 공개 관찰 가능 동작을 테스트합니다 . 여기서 "공개"는 반환 값 및 종속성과의 통신을 의미합니다.

"단위"는 동일한 문제를 해결하는 코드입니다 (보다 정확하게는 변경해야 할 이유가 동일 함). 단일 메소드 또는 많은 클래스 일 수 있습니다.

테스트하고 싶지 않은 주된 이유 private methods구현 세부 사항 이며 리팩토링 중에 변경하고 싶을 수도 있습니다 (기능을 변경하지 않고 OO 원칙을 적용하여 코드를 향상시킬 수 있음). 이것은 리팩토링 중에 CuT 의 동작 이 변경되지 않았 음을 보장하기 위해 단위 테스트를 변경하지 않으려는 경우입니다.

그러나 공용 인터페이스를 테스트 할 수 있도록 gazillion 클래스를 원하지 않고 공개 클래스를 테스트하면 많은 클래스에서 많은 의존성을 조롱해야하며 단위 테스트는 다음과 같습니다. 엄청나고 따르기가 어렵다.

나는 보통 반대를 경험한다. 클래스가 작을수록 (책임이 적을수록) 의존성이 적고, 읽고 쓰는 단위 테스트가 더 쉽다.

이상적인 수준의 추상화 패턴을 클래스에 적용하는 것이 이상적 입니다. 이것은 클래스가 비즈니스 로직을 제공하거나 (자체 상태를 유지하지 않고 매개 변수에 대해서만 작동하는 "순수한 함수") (x) 동시에 다른 객체에 대해 메소드를 호출 함을 의미합니다.

비즈니스 동작을 유닛 테스트이 방법은 케이크 한 조각과 "위임"객체가 보통입니다 실패하지 너무 간단한 더 유닛 테스트가 필요하지 않습니다 자신의 시험이에 남아있을 수 있도록하는 것이 (더 분기, 어떤 상태 변화)를 통합 또는 모듈 테스트


1

단위 테스트는 코드에서 작업하는 유일한 프로그래머 일 때 특히 유용합니다. 특히 응용 프로그램이 매우 크거나 매우 복잡한 경우입니다. 단위 테스트가 필수가되는 곳은 동일한 코드베이스에서 많은 수의 프로그래머가 작업하는 경우입니다. 이러한 대규모 팀에서 일하기 어려운 문제를 해결하기 위해 단위 테스트 개념이 도입되었습니다.

단위 테스트가 더 큰 팀을 돕는 이유는 계약에 관한 것입니다. 내 코드가 다른 사람이 작성한 코드를 호출하는 경우 다양한 상황에서 다른 사람의 코드가 수행 할 작업에 대해 가정합니다. 이러한 가정이 여전히 유효하다면 내 코드는 여전히 작동하지만 어떤 가정이 유효한지 어떻게 알 수 있으며 이러한 가정이 언제 바뀌 었는지 어떻게 알 수 있습니까?

여기에서 단위 테스트가 시작됩니다. 클래스 작성자는 클래스의 예상 동작을 문서화하기 위해 단위 테스트를 만듭니다. 단위 테스트는 클래스를 사용하는 모든 유효한 방법을 정의하고 단위 테스트를 실행하면 이러한 사용 사례가 예상대로 작동하는지 확인합니다. 클래스를 사용하려는 다른 프로그래머는 클래스 테스트를 읽고 클래스에 대해 기대할 수있는 동작을 이해하고 클래스 작동 방식에 대한 가정의 기초로 사용할 수 있습니다.

이런 식으로 클래스의 공용 메소드 서명과 단위 테스트는 클래스 작성자와 코드에서이 클래스를 사용하는 다른 프로그래머 간의 계약을 형성합니다.

이 시나리오에서 개인 메소드 테스트를 포함 시키면 어떻게됩니까? 분명히 말이되지 않습니다.

코드에서 작업하는 유일한 프로그래머이고 코드를 디버깅하는 방법으로 단위 테스트를 사용하려는 경우 아무런 해를 끼치 지 않으며 도구 일뿐이며 작동하는 방식으로 사용할 수 있습니다 그러나 단위 테스트가 도입 된 이유는 아니 었으며 단위 테스트의 주요 이점을 제공하지는 않습니다.


나는 의존성을 모방하여 의존성이 모의되면 행동이 바뀌더라도 테스트가 실패하지 않는다는 점에서 어려움을 겪고 있습니다. 이 실패는 단위 테스트가 아닌 통합 테스트에서 발생합니까?
Todd

모의는 실제 구현과 동일하게 작동하지만 종속성이 없습니다. 실제 구현이 변경되어 현재와 다른 경우 통합 테스트 실패로 표시됩니다. 개인적으로 모의 개발과 실제 구현을 하나의 작업으로 간주합니다. 단위 테스트 작성의 일부로 모형을 만들지 않습니다. 이런 식으로 클래스 동작을 변경하고 일치하도록 모의 객체를 변경하면 단위 테스트를 실행하면이 변경으로 인해 깨진 다른 모든 클래스가 식별됩니다.
bikeman868

1

그러한 질문에 대답하기 전에 실제로 달성하고자하는 것을 결정해야합니다.

당신은 코드를 작성합니다. 계약이 이행되기를 희망합니다 (즉,해야 할 일을합니다.해야 할 일을 적는 것은 일부 사람들에게는 큰 발전입니다).

코드가 수행해야 할 일을 합리적으로 확신하려면, 코드를 충분히 쳐다 보거나 "코드가 모든 테스트를 통과하면 정확하다"는 사실을 확신 할 수있는 충분한 사례를 테스트하는 테스트 코드를 작성하십시오.

종종 일부 코드의 공개적으로 정의 된 인터페이스에만 관심이 있습니다. 나는 당신의 라이브러리를 사용하는 경우, 나는 그것이 단지, 당신이 그것을 제대로 작동하게하는 방법을 상관하지 않습니다 않는 제대로 일을. 단위 테스트를 수행하여 라이브러리가 올바른지 확인합니다.

그러나 당신은 도서관을 만들고 있습니다. 제대로 작동하려면 달성하기 어려울 수 있습니다. X 작업을 올바르게 수행하는 라이브러리에 대해서만 신경을 쓰므로 X에 대한 단위 테스트가 있습니다. 라이브러리를 생성하는 개발자는 A, B 및 C 단계를 완전히 결합하여 X를 구현합니다. 라이브러리를 작동 시키려면 테스트를 추가하여 A, B 및 C가 각각 올바르게 작동하는지 확인하십시오. 이 테스트를 원합니다. "개인 메소드에 대한 단위 테스트가 없어야한다"고 말하는 것은 의미가 없습니다. 당신은 이러한 개인 방법에 대한 테스트를합니다. 어쩌면 누군가 개인 단위 테스트 방법이 잘못되었다고 말할 수도 있습니다. 그러나 그것은 단지 당신이 그것들을 "단위 테스트"라고 부르지 않고 "개인 테스트"또는 당신이 부르고 싶은 것을 부를 수 있다는 것을 의미합니다.

Swift 언어는 함수에 "testable"속성을 부여하여 테스트하기 때문에 A, B, C를 공개 메소드로 노출하지 않으려는 문제를 해결합니다. 컴파일러를 사용하면 테스트 할 수없는 코드가 아닌 단위 테스트에서 개인 테스트 가능 메소드를 호출 할 수 있습니다.


0

예, 당신은 미쳤어 요 .... 여우처럼!

개인 메소드를 테스트하는 몇 가지 방법이 있으며 그 중 일부는 언어에 따라 다릅니다.

  • 반사! 규칙이 깨졌습니다!
  • 그들을 보호하고 상속하고 재정의하십시오.
  • 친구 / 내부 인 VisibleTo 클래스

전체적으로 개인 메소드를 테스트하려는 경우 종속성에 대해 공개 메소드로 이동하고 테스트 / 주입하십시오.


잘 모르겠습니다. 내 눈에는 그것이 좋은 생각이 아니라 질문에 계속 대답했다고 설명했습니다
Liath

나는 모든 기지를 다룬다 고 생각했다 :(
Ewan

3
개인 헬퍼 메소드를 공개 API에 노출하여 테스트하는 것만으로도 미친 생각이 들었습니다. 항상 그렇게 생각했습니다.
Robert Harvey

0

실용적입니다. 인스턴스 상태를 공개 메소드로 설정하여 이러한 경우가 발생하도록 프라이빗 메소드에서 특수 케이스를 테스트하는 것은 종종 너무 복잡합니다.

이러한 "비공개"메서드를 테스트하기 위해 추가 internal접근 자 ( InternalsVisibleTo테스트 어셈블리 플래그와 함께 )를 명확하게 명명 DoSomethingForTesting(parameters)했습니다.

물론, 구현은 때때로 변경 될 수 있으며, 테스트 접근자를 포함한 테스트는 더 이상 사용되지 않습니다. 그것은 테스트되지 않은 경우 나 읽을 수없는 테스트보다 여전히 낫습니다.

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