테스트 주도 개발
Test-driven development
테스트 주도 개발(TDD)은 매우 짧은 개발 사이클에 의존하는 소프트웨어 개발 프로세스입니다. 첫째로 개발자는 새로운 함수나 원하는 향상을 정의하면서 1. (처음에 실패할) 자동화된 테스트 케이스를 작성하고, 2. 그 테스트를 통과할 최소의 코드를 제작하며, 마지막으로 3. 받아들일 수 있는 표준으로 새로운 코드를 리팩토링 합니다. 이 기술을 개발해 왔고 재발견한 Kent Beck은 TDD가 간단한 설계와 자신감을 북돋게 한다고 2003년에 주장하였습니다.
Test-driven development (TDD) is a software development process that relies on the repetition of a very short development cycle: first the developer writes an (initially failing) automated test case that defines a desired improvement or new function, then produces the minimum amount of code to pass that test, and finally refactors the new code to acceptable standards. Kent Beck, who is credited with having developed or 'rediscovered'[1] the technique, stated in 2003 that TDD encourages simple designs and inspires confidence.[2]
테스트 주도 개발은 1999년에 시작한 XP의 테스트 우선 개발과 관련 있지만, 최근들어 자신의 권리에 더 관심이 있는 듯 합니다.
Test-driven development is related to the test-first programming concepts of extreme programming, begun in 1999,[3] but more recently has created more general interest in its own right.[4]
프로그래머들은 더 오래된 기술로 개발된 레거시 코드를 디버깅하고 향상시키기 위해 이 컨셉을 적용합니다.
Programmers also apply the concept to improving and debugging legacy code developed with older techniques.
테스트 주도 개발 주기
Test-driven development cycle
- 테스트를 추가하기
- Add a Test
테스트 주도 개발에서 각각 새로운 특징은 테스트를 작성하는 것으로 시작한다는 점입니다. 테스트를 작성하기 위해 개발자는 분명하게 업무 상세와 요구사항을 이해하여야 합니다. 개발자는 이를 요구사항과 예외 조건을 만족하기 위해 use cases와 user story를 통해 달성할 수 있고 소프트웨어 환경에 적절한 테스팅 프레임워크에서 테스트를 작성할 수 있습니다. 이미 있는 테스트의 수정된 버전이 될 수도 있습니다. 이는 테스트 주도 개발과 코드가 쓰여진 후 유닛테스트와 구별되는 특징입니다. 코드를 작성하기 전에 개발자로 하여금 요구사항에 집중하도록 합니다. 미묘하지만 중요한 차이입니다.
In test-driven development, each new feature begins with writing a test. To write a test, the developer must clearly understand the feature's specification and requirements. The developer can accomplish this through use cases and user stories to cover the requirements and exception conditions, and can write the test in whatever testing framework is appropriate to the software environment. It could be a modified version of an existing test. This is a differentiating feature of test-driven development versus writing unit tests after the code is written: it makes the developer focus on the requirements before writing the code, a subtle but important difference.
2. 모든 테스트를 실행하고 실패한 것을 알아보기
2. Run all tests and see if the new one fails
이는 어떤 새로운 코드 요구하는 거 없이 새로운 테스트가 실수 없이 통과하고 요구된 특징이 이미 존재하지 않는지에 대해 테스트 자동화 도구(자동화된 테스트 프레임워크)가 정확히 작동하는지 검증합니다. 이 단계는 그 테스트 자체를 검사합니다. 반대로 새로운 테스트가 항상 통과할 가능성을 정하기 때문에 유용합니다. 새로운 테스트는 기대한 이유에 대해 실패할 수 있습니다. 이 단계는 정확한 제약조건에서 유닛테스트가 테스트되고 있는지 의도된 경우에서만 통과하는지 개발자에게 자신감을 심어줄 수 있도록 합니다.
This validates that the test harness is working correctly, that the new test does not mistakenly pass without requiring any new code, and that the required feature does not already exist. This step also tests the test itself, in the negative: it rules out the possibility that the new test always passes, and therefore is worthless. The new test should also fail for the expected reason. This step increases the developer's confidence that the unit test is testing the correct constraint, and passes only in intended cases.
3. 일부 코드를 작성하기
3. Write some code
이 단계는 테스트를 통과하는데 몇몇 코드를 작성합니다. 이 단계에서 쓰여진 새로운 코드는 완벽하지 않은데 예를 들어 우아하지 않는 방법으로 테스트를 통과합니다. 이는 받아들일만 한데 5단계에서 코드의 질이 높아질 것이기 때문입니다. 요점은 이 단계의 목적은 테스트를 통과하는 것입니다. 더이상 (테스트를 하지 않는) 기능은 예측되지 않으며 어떤 단계에서도 '허용되지' 않을 것입니다.
The next step is to write some code that causes the test to pass. The new code written at this stage is not perfect and may, for example, pass the test in an inelegant way. That is acceptable because it will be improved and honed in Step 5.
At this point, the only purpose of the written code is to pass the test; no further (and therefore untested) functionality should be predicted nor 'allowed for' at any stage.
4. 테스트 실행하기
4. Run tests
모든 테스트 케이스가 통과하였다면 새로운 코드는 테스트 요구사항을 만족하며 현재 존재하는 특징에서 지위를 낮추거나 멈출 필요가 없이 프로그래머는 자신감을 가질 수 있습니다. 그렇지 않으면 새로운 코드는 통과할 때까지 수정되어야 합니다.
If all test cases now pass, the programmer can be confident that the new code meets the test requirements, and does not break or degrade any existing features. If they do not, the new code must be adjusted until they do.
5. 코드를 리팩토링하기
5. Refactor code
증가하는 코드는 테스트 주도 개발 동안에 정기적으로 정리되어야 합니다. 새로운 코드는 더 논리적으로 테스트에 통과되기에 편리하도록 바뀌어야 합니다. 중복은 제거되어야 합니다. 부가 기능이 추가될 때 객체, 클래스, 모듈, 변수와 메소드 이름은 현재 목적과 사용을 분명히 표현해야 합니다. 특징이 추가됨으로서 메소드의 body는 더 길어지며 다른 객체들도 더 커질 것입니다. 소프트웨어 라이프사이클에서 나중에 가치가 있기 위한 가독성 및 유지보수를 향상시키기 위해 주의깊게 더 커진 body 부분을 명명하고 코드를 쪼개면 이득을 볼 수 있습니다. 상속 관계는 더욱 논리적으로 정리되게 도울 것이며 디자인 패턴으로 알려진 방법으로 이득을 볼 수 있습니다. 깔끔한 코드를 작성하고 리팩토링하는 상세하고 일반적인 가이드라인이 있습니다. 각 리팩토링 구간동안 테스트 케이스들을 계속해서 재실행함으로서 개발자는 현재 기능을 수정하기 않는 프로세스를 만들 수 있습니다.
The growing code base must be cleaned up regularly during test-driven development. New code can be moved from where it was convenient for passing a test to where it more logically belongs. Duplication must be removed. Object, class, module, variable and method names should clearly represent their current purpose and use, as extra functionality is added. As features are added, method bodies can get longer and other objects larger. They benefit from being split and their parts carefully named to improve readability and maintainability, which will be increasingly valuable later in the software lifecycle. Inheritance hierarchies may be rearranged to be more logical and helpful, and perhaps to benefit from recognised design patterns. There are specific and general guidelines for refactoring and for creating clean code.[6][7] By continually re-running the test cases throughout each refactoring phase, the developer can be confident that process is not altering any existing functionality.
소프트웨어 디자인에서 중복을 제거하는 개념은 중요한 요소입니다. 그러나 이 경우 테스트 코드와 운영 코드 사이에 중복 제거를 적용할 수도 있습니다.
The concept of removing duplication is an important aspect of any software design. In this case, however, it also applies to the removal of any duplication between the test code and the production code—for example magic numbers or strings repeated in both to make the test pass in Step 3.
반복
Repeat
새로운 테스트를 시작하고 사이클은 다음 기능으로 반복됩니다. 각 단계의 크기는 각 테스트 사이에 1~10번정도 교정할 정도로 항상 작아야 합니다. 새로운 코드가 새로운 테스트를 갑자기 만족하지 않는다거나 다른 테스트가 예상치 못하게 실패한다면 프로그래머는 이 작업을 undo하거나 과도한 디버깅보다는 우선 이전 소스로 복귀해야 합니다. 계속된 통합은 되돌릴 수 있는 체크포인트를 제공하는 데 도움을 줍니다. 외부 라이브러리를 사용할 때 단기 그 라이브러리 자체를 테스트 하기 위한 코드 추가를 하지 않도록 하는 게 중요한데, 그렇지 않으면 개발 중인 모든 소프트웨어의 요구를 제공하기 위해 충분하지 못한 특징이나 라이브러리에 이유가 있다고 판단할 수 있기 때문입다.
Starting with another new test, the cycle is then repeated to push forward the functionality. The size of the steps should always be small, with as few as 1 to 10 edits between each test run. If new code does not rapidly satisfy a new test, or other tests fail unexpectedly, the programmer should undo or revert in preference to excessive debugging. Continuous integration helps by providing revertible checkpoints. When using external libraries it is important not to make increments that are so small as to be effectively merely testing the library itself,[4] unless there is some reason to believe that the library is buggy or is not sufficiently feature-complete to serve all the needs of the software under development.