TDD 개발에서 일반적으로 가장 먼저하는 일은 인터페이스를 만든 다음 해당 인터페이스에 대한 단위 테스트 작성을 시작하는 것입니다. TDD 프로세스를 진행함에 따라 인터페이스를 구현하는 클래스를 생성하고 어느 시점에서 유닛 테스트를 통과하게됩니다.
이제 내 질문은 인터페이스에 의해 노출 된 메서드 / 속성을 지원하기 위해 클래스에 작성해야 할 수있는 개인 및 보호 메서드에 대한 것입니다.
-
클래스의 개인 메서드에 자체 단위 테스트가 있어야합니까?
-
클래스의 보호 된 메서드에 자체 단위 테스트가 있어야합니까?
내 생각:
-
특히 인터페이스를 코딩하고 있기 때문에 보호 / 비공개 메서드는 블랙 박스이므로 걱정할 필요가 없습니다.
-
인터페이스를 사용하고 있기 때문에 정의 된 계약이 인터페이스를 구현하는 다른 클래스에 의해 올바르게 구현되었는지 확인하기 위해 단위 테스트를 작성하고 있습니다. 따라서 다시 한 번 private / protected 메서드에 대해 걱정해서는 안되며 다음을 호출하는 단위 테스트를 통해 실행되어야합니다. 인터페이스에 의해 정의 된 메소드 / 속성.
-
내 코드 커버리지에 보호 / 비공개 메서드가 적중 된 것으로 표시되지 않으면 올바른 단위 테스트가 없거나 사용되지 않고 제거해야하는 코드가있는 것입니다.
답변
아니요, 개인 또는 보호 방법을 테스트 할 생각은 없습니다. 클래스의 private 및 protected 메서드는 공용 인터페이스의 일부가 아니므로 공용 동작을 노출하지 않습니다. 일반적으로 이러한 메서드는 테스트를 녹색으로 설정 한 후 적용하는 리팩토링에 의해 생성됩니다.
따라서 이러한 개인 메서드는 공용 인터페이스의 동작을 주장하는 테스트에 의해 암시 적 으로 테스트됩니다.
좀 더 철학적 인 메모에서, 당신은 방법이 아니라 행동을 테스트하고 있다는 것을 기억하세요. 따라서 테스트중인 클래스가 수행 할 수있는 일련의 작업을 생각한다면 클래스가 예상대로 작동하는지 테스트하고 주장 할 수있는 한 클래스에서 내부적으로 구현하는 데 사용되는 개인 (및 보호 된) 메서드가 있는지 여부 그 행동은 무관합니다. 이러한 메서드는 공개 동작의 구현 세부 정보입니다.
답변
나는 대부분의 포스터에 동의하지 않습니다.
가장 중요한 규칙은 다음과 같습니다. 작업 코드는 공개 / 보호 / 사설에 대한 이론적 규칙을 무시합니다.
코드를 철저히 테스트해야합니다. 공개 메소드에 대한 테스트를 작성하여 보호 / 비공개 메소드를 충분히 수행 할 수 있다면 좋습니다.
할 수 없다면 리팩터링하여 할 수 있도록하거나 보호 / 비공개 규칙을 구부립니다.
아이들에게 시험을 준 심리학자에 대한 멋진 이야기가 있습니다. 그는 각 어린이에게 밧줄이 달린 나무 판 두 개를 양 끝에주고 가능한 한 빨리 발을 바닥에 대지 않고 방을 건너도록 요청했습니다. 모든 아이들은 작은 스키처럼 보드를 각 보드에 한 발씩 밧줄로 잡고 바닥을 가로 질러 미끄러졌습니다. 그런 다음 그는 그들에게 똑같은 임무를 주었지만 보드는 하나만 사용했습니다. 그들은 단일 보드의 양쪽 끝에 1 피트 씩 바닥을 가로 질러 회전 / “걷습니다”. 그리고 그들은 더 빠릅니다!
Java (또는 모든 언어)에 기능 (개인 / 보호 / 공개)이 있다고해서 반드시 사용하기 때문에 더 나은 코드를 작성하는 것은 아닙니다!
이제 항상 이러한 충돌을 최적화 / 최소화하는 방법이 있습니다. 대부분의 언어에서 메서드를 public 대신 보호하고 동일한 패키지 (또는 기타)에 테스트 클래스를 넣을 수 있으며 메서드를 테스트에 사용할 수 있습니다. 다른 포스터에 설명 된대로 도움이 될 수있는 주석이 있습니다. 리플렉션을 사용하여 개인 메서드를 얻을 수 있습니다 (yuck).
맥락도 중요합니다. 외부 사용자가 사용할 API를 작성하는 경우 공개 / 개인이 더 중요합니다. 내부 프로젝트라면 누가 정말 신경 쓰나요?
그러나 하루가 끝나면 테스트 부족으로 인해 얼마나 많은 버그가 발생했는지 생각해보십시오. 그런 다음 “과도하게 보이는”방법으로 인해 발생한 버그 수를 비교합니다. 그 대답이 당신의 결정을 이끌어 줄 것입니다.
답변
당신은 다음과 같이 썼습니다.
TDD 개발에서 일반적으로 가장 먼저하는 일은 인터페이스를 만든 다음 해당 인터페이스에 대한 단위 테스트 작성을 시작하는 것입니다. TDD 프로세스를 진행함에 따라 인터페이스를 구현하는 클래스를 생성하고 어느 시점에서 유닛 테스트를 통과하게됩니다.
BDD 언어로 다시 말씀 드리겠습니다 .
클래스가 가치있는 이유와 동작 방식을 설명 할 때 일반적으로 가장 먼저하는 일은 인터페이스 *를 통해 클래스를 사용하는 방법에 대한 예제를 만드는 것입니다. 원하는 동작을 추가하면 해당 값을 제공하는 클래스가 생성되고 어느 시점에서 예제가 작동합니다.
* 실제
Interface
또는 단순히 클래스의 액세스 가능한 API 일 수 있습니다. 예 : Ruby에는 인터페이스가 없습니다.
이것이 개인 메서드를 테스트하지 않는 이유입니다. 테스트는 클래스를 사용하는 방법의 예이며 실제로 사용할 수 없기 때문입니다. 원하는 경우 개인 메서드의 책임을 공동 작업 클래스에 위임 한 다음 해당 도우미를 모의 / 스텁하는 것이 좋습니다.
보호 된 메서드를 사용하면 클래스를 확장하는 클래스가 특정 동작을 가져야하고 어떤 가치를 제공해야한다고 말합니다. 그런 다음 클래스의 확장을 사용하여 해당 동작을 보여줄 수 있습니다. 예를 들어, 정렬 된 컬렉션 클래스를 작성하는 경우 동일한 내용을 가진 두 확장이 동등 함을 보여 주 었음을 보여줄 수 있습니다.
도움이 되었기를 바랍니다!
답변
클래스에 대한 단위 테스트를 작성할 때 클래스의 기능이 공용 인터페이스의 메서드에서 직접 구현되는지 또는 일련의 전용 메서드에서 구현되는지 여부에 반드시 신경 쓰지 않아도됩니다. 그렇습니다. 개인 메서드를 테스트해야하지만 그렇게하기 위해 테스트 코드에서 직접 호출 할 필요는 없습니다 (개인 메서드를 직접 테스트하면 구현이 테스트에 밀접하게 연결되어 리팩토링이 불필요하게 어려워집니다).
보호 된 메서드는 클래스와 미래의 자식간에 서로 다른 계약을 형성하므로 계약이 잘 정의되고 실행되는지 확인하려면 공용 인터페이스와 비슷한 범위로 실제로 테스트해야합니다.
답변
아니! 인터페이스 만 테스트하십시오.
TDD의 큰 이점 중 하나는 비공개 메서드를 구현하기로 선택한 방법에 관계없이 인터페이스가 작동하도록 보장하는 것입니다.
답변
다른 사람들이 위에서 말한 것을 완료하면 보호 된 메서드는 일종의 인터페이스의 일부라고 말할 수 있습니다. 인터페이스를 고려할 때 모든 사람이 생각하는 경향이있는 구성 대신 상속에 노출 된 메서드 일뿐입니다.
메서드를 private 대신 보호 됨으로 표시하면 타사 코드에서 사용할 것으로 예상되므로 상속 및 구성을 위해 열려있는 공용 메서드에 의해 정의 된 일반 인터페이스에서 발생하는 것처럼 일종의 계약을 정의하고 테스트해야합니다. .
답변
테스트를 작성하는 데는 두 가지 이유가 있습니다.
- 예상되는 동작 주장
- 행동 회귀 방지
취하기 (1) 예상되는 행동 주장 :
예상되는 동작을 주장 할 때 코드가 예상대로 작동하는지 확인해야합니다. 이것은 모든 종류의 코드를 구현할 때 모든 개발자가 수행하는 일상적인 수동 확인을 수행하는 자동화 된 방법입니다.
- 내가 방금 쓴 것이 효과가 있었습니까?
- 이 루프가 실제로 종료됩니까?
- 내가 생각하는 순서대로 반복됩니까?
- null 입력에 대해 작동합니까?
이것들은 우리 모두가 머릿속에서 대답하는 질문이며, 일반적으로 우리는 코드를 머릿속에서도 실행하려고 시도합니다. 제대로 작동하는지 확인합니다. 이러한 경우 컴퓨터가 명확한 방식으로 응답하도록하는 것이 유용한 경우가 많습니다. 그래서 우리는 그것을 주장하는 단위 테스트를 작성합니다. 이를 통해 코드에 대한 자신감을 얻고 결함을 조기에 발견 할 수 있으며 실제로 코드를 구현하는 데 도움이 될 수도 있습니다.
필요할 때마다이 작업을 수행하는 것이 좋습니다. 이해하기 조금 까다 롭거나 사소하지 않은 모든 코드. 사소한 코드조차도 이점을 얻을 수 있습니다. 그것은 모두 자신의 자신감에 관한 것입니다. 얼마나 자주하고 얼마나 멀리 갈 것인지는 자신의 만족도에 달려 있습니다. 확실하게 예라고 답할 수있을 때 중지하십시오.
이런 종류의 테스트에서는 가시성, 인터페이스 또는 그 어떤 것도 신경 쓰지 않고 작동하는 코드 만 신경 쓰게됩니다. 예, 질문에 예라고 답하기 위해 테스트를 받아야한다고 생각되면 개인 및 보호 방법을 테스트합니다.
취해야 할 사항 (2) 행동 회귀 방지 :
작동하는 코드를 얻은 후에는이 코드를 향후 손상으로부터 보호 할 수있는 메커니즘을 마련해야합니다. 아무도 당신의 소스와 당신의 구성을 다시는 건드리지 않았다면 이것이 필요하지 않을 것이지만, 대부분의 경우 당신이나 다른 사람들은 당신의 소프트웨어의 소스와 구성을 건드릴 것입니다. 이 내부 조작은 작업 코드를 손상시킬 가능성이 높습니다.
메커니즘은 이러한 손상으로부터 보호하기위한 방법으로 이미 대부분의 언어로 존재합니다. 가시성 기능은 하나의 메커니즘입니다. 개인 메서드는 격리되고 숨겨집니다. 캡슐화는 사물을 구획화하는 또 다른 메커니즘으로, 다른 구획을 변경해도 다른 구획에 영향을주지 않습니다.
이를위한 일반적인 메커니즘은 경계에 대한 코딩입니다. 코드 부분 사이에 경계를 만들어 경계 안의 모든 것을 외부로부터 보호합니다. 경계는 상호 작용의 지점이되고 사물이 상호 작용하는 계약이됩니다.
즉, 인터페이스를 깨거나 예상되는 동작을 깨는 방식으로 경계를 변경하면 해당 경계에 의존하는 다른 경계가 손상되고 깨질 수 있습니다. 그렇기 때문에 이러한 경계를 대상으로하고 의미와 동작이 변경되지 않는다고 단언하는 단위 테스트를 갖는 것이 좋습니다.
이것은 일반적인 단위 테스트로, TDD 또는 BDD를 언급 할 때 가장 많이 말하는 것입니다. 요점은 경계를 강화하고 변경으로부터 보호하는 것입니다. private 메서드는 경계가 아니기 때문에이를 위해 private 메서드를 테스트하고 싶지 않습니다. 보호 된 방법은 제한적이며 보호 할 것입니다. 그들은 세계에 노출되지 않지만 여전히 다른 구획 또는 “유닛”에 노출되어 있습니다.
이것을 어떻게 만들까요?
지금까지 살펴본 것처럼 인터페이스가 변경되지 않는다고 주장하기 위해 공용 및 보호 된 메서드를 단위 테스트해야하는 좋은 이유가 있습니다. 또한 우리의 구현이 작동한다고 주장하기 위해 private 메서드를 테스트 할 좋은 이유가 있습니다. 그럼 모두 단위 테스트를해야할까요?
예 그리고 아니오.
첫째 , 가시성에 관계없이 코드가 작동한다는 확신을 가질 수 있도록 대부분의 경우에 작동한다는 확실한 증거가 필요하다고 생각하는 모든 메서드를 테스트합니다. 그런 다음 해당 테스트를 비활성화하십시오. 그들은 그곳에서 일을했습니다.
마지막으로 : 경계 테스트를 작성하십시오. 시스템의 다른 장치에서 사용할 각 포인트에 대해 단위 테스트를하십시오. 이 테스트가 의미 론적 계약, 메서드 이름, 인수 수 등을 주장하는지 확인하십시오. 또한 테스트가 단위의 사용 가능한 동작을 주장하는지 확인하십시오. 테스트는 장치 사용 방법과 장치가 할 수있는 작업을 보여 주어야합니다. 모든 코드 푸시에서 실행되도록 이러한 테스트를 활성화 상태로 유지하십시오.
참고 : 첫 번째 테스트 세트를 비활성화 한 이유는 리팩토링 작업이 발생하도록 허용하기 위해서입니다. 활성 테스트는 코드 커플 링입니다. 테스트중인 코드의 향후 수정을 방지합니다. 인터페이스 및 상호 작용 계약에만 이것을 원합니다.