내가 TDD에 대해 알게 된 것은 테스트를 설정하는 데 시간이 걸리고 자연스럽게 게으르다는 것입니다. 저는 항상 가능한 한 적은 코드를 작성하고 싶습니다. 내가하는 첫 번째 일은 내 생성자가 모든 속성을 설정했지만 이것이 과잉입니까?
내 질문은 단위 테스트를 어떤 수준으로 작성합니까?
.. 너무 많은 테스트 사례가 있나요?
답변:
나는 테스트가 아니라 작동하는 코드에 대해 돈을 받는다. 그래서 나의 철학은 주어진 신뢰 수준에 도달하기 위해 가능한 한 적은 테스트를하는 것이다. . 일반적으로 생성자에 잘못된 변수를 설정하는 것과 같은 실수를하지 않으면 테스트하지 않습니다. 나는 테스트 오류를 이해하는 경향이 있으므로 복잡한 조건이있는 논리가있을 때 특히주의합니다. 팀에서 코딩 할 때, 저는 우리가 전체적으로 잘못되는 경향이있는 코드를 신중하게 테스트하기 위해 전략을 수정합니다.
다른 사람들은이 철학에 기반한 다른 테스트 전략을 가지고있을 것이지만, 테스트가 코딩의 내부 루프에 가장 잘 맞을 수있는 방법에 대한 미성숙 한 이해 상태를 감안할 때 나에게는 합리적으로 보입니다. 이제 10 년 또는 20 년 후에 우리는 어떤 테스트를 작성하고, 어떤 테스트를 작성하지 않으며, 차이점을 어떻게 구분하는지에 대한보다 보편적 인 이론을 갖게 될 것입니다. 그 동안 실험은 순서대로 보인다.
깨질 것으로 예상되는 항목과 엣지 케이스에 대한 단위 테스트를 작성하십시오. 그 후에 버그에 대한 수정을 작성하기 전에 버그 보고서가 들어 오면 테스트 케이스를 추가해야합니다. 개발자는 다음을 확신 할 수 있습니다.
첨부 된 주석에 따라-시간이 지남에 따라 주어진 클래스에서 많은 버그가 발견되면 단위 테스트 작성에 대한 이러한 접근 방식이 문제를 일으킬 수 있다고 생각합니다. 이것은 아마도 재량권이 도움이 될 것입니다.-다시 발생할 가능성이있는 버그에 대해서만 단위 테스트를 추가하거나 그 재발이 심각한 문제를 일으킬 수있는 곳입니다. 단위 테스트에서 통합 테스트의 척도가 이러한 시나리오에서 도움이 될 수 있음을 발견했습니다. 상위 코드 경로를 테스트하면 하위 코드 경로를 포함 할 수 있습니다.
모든 것이 가능한 한 단순해야하지만 더 단순해서는 안됩니다. -A. 아인슈타인
TDD에 대해 가장 오해받는 것 중 하나는 그 안에있는 첫 번째 단어입니다. 테스트. 이것이 BDD가 등장한 이유입니다. 사람들은 첫 번째 D가 중요한 것, 즉 Driven이라는 것을 실제로 이해하지 못했기 때문입니다. 우리 모두는 테스트에 대해 조금 또는 많이 생각하고 디자인 추진에 대해 조금 또는 조금 생각하는 경향이 있습니다. 그리고 이것은 귀하의 질문에 대한 모호한 대답이라고 생각합니다. 그러나 실제로 테스트하는 대신 코드를 구동하는 방법을 고려해야합니다. 그것은 Coverage-tool이 당신을 도울 수있는 것입니다. 디자인은 훨씬 더 크고 문제가되는 문제입니다.
"모든 것"테스트를 제안하는 사람들에게 : "완전히 테스트"하는 방법 int square(int x)
은 공통 언어 및 일반적인 환경에서 약 40 억 개의 테스트 케이스가 필요 하다는 것을 인식하십시오 .
사실, 그보다 훨씬 더 나쁜 : 방법은 void setX(int newX)
또한 의무가 없습니다 이외의 다른 멤버의 값을 변경하는 x
- 당신이를 테스트하고 obj.y
, obj.z
모든 호출 한 후 변경되지 않은 상태로 유지 등 obj.setX(42);
?
"모든 것"의 일부만 테스트하는 것이 실용적입니다. 이것을 받아 들인 후에는 믿을 수 없을 정도로 기본적인 행동을 테스트하지 않는 것을 고려하는 것이 더 맛있어집니다. 모든 프로그래머는 버그 위치 의 확률 분포 를 가지고 있습니다. 현명한 접근 방식은 버그 확률이 높을 것으로 예상되는 테스트 지역에 에너지를 집중하는 것입니다.
고전적인 대답은 "파손될 수있는 모든 것을 테스트"하는 것입니다. set 또는 get 외에는 아무것도하지 않는 setter와 getter를 테스트하는 것이 아마도 너무 많은 테스트이므로 시간이 걸리지 않는다는 의미로 해석합니다. IDE가 당신을 위해 작성하지 않는 한, 당신도 그렇게 할 수 있습니다.
생성자 가 속성을 설정 하지 않으면 나중에 오류가 발생할 수있는 경우 해당 속성이 설정되었는지 테스트하는 것은 과도하지 않습니다.
지금 간단한 테스트를 건너 뛰는 문제의 일부는 향후 리팩토링으로 인해 많은 논리로 인해 간단한 속성이 매우 복잡해질 수 있다는 것입니다. 가장 좋은 아이디어는 테스트를 사용하여 모듈의 요구 사항을 확인할 수 있다는 것입니다. X를 통과했을 때 Y를 되 찾아야한다면 그것이 테스트하고 싶은 것입니다. 그런 다음 나중에 코드를 변경할 때 X가 Y를 제공하는지 확인하고 나중에 해당 요구 사항이 추가 될 때 A에 대한 테스트를 추가하여 B를 제공 할 수 있습니다.
초기 개발 테스트를 작성하는 동안 보낸 시간이 첫 번째 또는 두 번째 버그 수정에서 효과가 있다는 것을 발견했습니다. 3 개월 동안 살펴 보지 않은 코드를 선택하고 수정 사항이 모든 경우를 다루고 "아마도"어떤 것도 손상시키지 않는지 합리적으로 확신 할 수있는 능력은 매우 중요합니다. 또한 단위 테스트는 스택 추적을 넘어서는 버그를 분류하는 데 도움이된다는 것을 알게 될 것입니다. 앱의 개별 부분이 작동하고 실패하는 방식을 확인하면 전체적으로 작동하거나 실패하는 이유에 대한 큰 통찰력을 얻을 수 있습니다.
대부분의 경우에 논리가 있다면 테스트 해보자. 여기에는 생성자 및 속성이 포함되며, 특히 속성에 둘 이상의 항목이 설정되는 경우 더욱 그렇습니다.
너무 많은 테스트와 관련하여 논쟁의 여지가 있습니다. 어떤 사람들은 모든 것이 견고성을 위해 테스트되어야한다고 말하고, 다른 사람들은 효율적인 테스트를 위해 깨질 수있는 것 (즉, 로직) 만 테스트해야한다고 말합니다.
나는 개인적인 경험에서 두 번째 캠프에 더 의지하고 싶지만 누군가가 모든 것을 테스트하기로 결정했다면 그것이 너무 많았다 고 말하지 않을 것입니다.
그래서, 아니오 – 일반적인 의미에서 "너무 많은"테스트는 개인만을위한 것이 아니라고 말하고 싶습니다.
Test Driven Development는 모든 테스트가 통과되면 코딩을 중지하는 것을 의미합니다.
속성에 대한 테스트가없는 경우이를 구현해야하는 이유는 무엇입니까? "불법"할당의 경우 예상되는 동작을 테스트 / 정의하지 않으면 속성은 어떻게해야합니까?
그러므로 나는 전적으로 클래스가 보여야 할 모든 행동을 테스트하는 것입니다. "기본"속성을 포함합니다.
이 테스트를 더 쉽게하기 위해 TestFixture
값을 설정 / 가져 오기위한 확장 점을 제공하고 유효하고 잘못된 값 목록을 가져오고 속성이 올바르게 작동하는지 확인하는 단일 테스트가있는 간단한 NUnit 을 만들었습니다 . 단일 속성 테스트는 다음과 같습니다.
[TestFixture]
public class Test_MyObject_SomeProperty : PropertyTest<int>
{
private MyObject obj = null;
public override void SetUp() { obj = new MyObject(); }
public override void TearDown() { obj = null; }
public override int Get() { return obj.SomeProperty; }
public override Set(int value) { obj.SomeProperty = value; }
public override IEnumerable<int> SomeValidValues() { return new List() { 1,3,5,7 }; }
public override IEnumerable<int> SomeInvalidValues() { return new List() { 2,4,6 }; }
}
람다와 속성을 사용하면 더 간결하게 작성할 수도 있습니다. MBUnit은 이와 같은 것들을 기본적으로 지원합니다. 요점은 위의 코드가 속성의 의도를 포착한다는 것입니다.
추신 : 아마도 PropertyTest 에는 객체의 다른 속성이 변경되지 않았는지 확인하는 방법이 있어야합니다 . 흠 .. 다시 드로잉 보드로.
따라서 테스트를 작성하여 프로그래밍을 많이할수록 테스트의 세분성 수준에 대한 걱정이 줄어 듭니다. 되돌아 보면 내가 행동 을 검증한다는 목표를 달성하기 위해 가능한 가장 간단한 일을하고있는 것 같습니다 . 이것은 내 코드가 내가 요청한 작업을 수행하고 있다는 확신을 생성하고 있음을 의미하지만 내 코드가 버그가 없다는 절대적인 보장으로 간주되지는 않습니다. 올바른 균형은 표준 동작을 테스트하고 아마도 한두 개의 경우를 테스트 한 다음 내 디자인의 다음 부분으로 이동하는 것이라고 생각합니다.
나는 이것이 모든 버그를 다루지 않을 것이며이를 포착하기 위해 다른 전통적인 테스트 방법을 사용한다는 것을 인정합니다.
비즈니스 로직의 "핵심"에있는 모든 것을 테스트해야한다고 생각합니다. Getter 및 Setter도 허용하지 않을 수있는 음수 또는 null 값을 허용 할 수 있기 때문입니다. 시간이 있다면 (항상 상사에게 의존) 다른 비즈니스 로직과 이러한 개체를 호출하는 모든 컨트롤러를 테스트하는 것이 좋습니다 (단위 테스트에서 통합 테스트로 천천히 이동).
나는 부작용이없는 간단한 setter / getter 메서드를 단위 테스트하지 않습니다. 그러나 나는 다른 모든 공개 방법을 단위 테스트합니다. 알고리즘의 모든 경계 조건에 대한 테스트를 만들고 단위 테스트의 범위를 확인하려고합니다.
많은 일이지만 그만한 가치가 있다고 생각합니다. 디버거에서 코드를 단계별로 실행하는 것보다 코드 (심지어 테스트 코드 포함)를 작성하는 것이 좋습니다. 코드-빌드-배포-디버그주기는 매우 시간이 많이 걸리고 빌드에 통합 한 단위 테스트가 더 철저할수록 코드-빌드-배포-디버그주기를 거치는 시간이 줄어 듭니다.
왜 아키텍처를 코딩하고 있는지 말하지 않았습니다. 그러나 Java의 경우 Maven 2 , JUnit , DbUnit , Cobertura 및 EasyMock을 사용 합니다.
더 많이 읽을수록 일부 단위 테스트는 패턴과 비슷하다고 생각합니다. 언어가 부족한 냄새입니다.
사소한 게터가 실제로 올바른 값을 반환하는지 테스트해야 할 때, 이는 게터 이름과 멤버 변수 이름을 혼용 할 수 있기 때문입니다. 루비의 'attr_reader : name'을 입력하면 더 이상 일어날 수 없습니다. 자바에서는 불가능합니다.
게터가 사소하지 않은 경우 에도 테스트를 추가 할 수 있습니다.
이 답변은 중요도 / 중요성으로 인해 단위 테스트를 원하는 주어진 방법에 대해 사용할 단위 테스트 수를 파악하는 데 더 적합합니다. McCabe의 Basis Path Testing 기술을 사용 하면 다음을 수행하여 단순한 "문장 범위"또는 "분기 범위"보다 코드 범위 신뢰도를 양적으로 높일 수 있습니다.