기존 생산 프로젝트에 단위 테스트를 성공적으로 추가 할 수 있습니까? 그렇다면 어떻게 그리고 가치가 있습니까?
프로덕션중인 기존 프로젝트에 단위 테스트를 추가 할 것을 강력히 고려하고 있습니다. TDD (face palm)의 이점을 실제로보기 전에 18 개월 전에 시작 되었으므로 이제는 많은 프로젝트가있는 다소 큰 솔루션이며 단위 테스트를 추가하기 위해 어디에서 시작 해야할지 가장 어리석은 아이디어는 아닙니다. 내가 이것을 고려하게하는 것은 때때로 오래된 버그가 다시 나타나는 것처럼 보이거나 버그가 실제로 수정되지 않고 수정 된 것으로 체크인 된다는 것입니다. 단위 테스트는 이러한 문제 발생을 줄이거 나 방지합니다.
SO에 대한 비슷한 질문을 읽음으로써 버그 추적기에서 시작하고 회귀를 막기 위해 각 버그에 대한 테스트 사례를 작성하는 것과 같은 권장 사항을 보았습니다. 그러나 나는 큰 그림을 잃어 버리고 결국 TDD를 사용하면 포함 된 기본 테스트가 누락 될까 걱정하고 있습니다.
기존 솔루션이 제대로 단위 테스트를 거치지 않고 제대로 테스트 되도록하기 위해 준수해야하는 프로세스 / 단계가 있습니까? 테스트 품질 이 좋고 테스트가 아닌 테스트가 테스트가 아닌 것보다 낫다 는 것을 어떻게 보장 할 수 있습니까 ?
그래서 나는 또한 요구하는 것이 같아요.
- 프로덕션 환경에있는 기존 솔루션에 대한 노력의 가치가 있습니까?
- 이 프로젝트의 테스트를 무시하고 나중에 다시 작성할 수 있도록 추가하는 것이 더 좋습니까?
- 더 유익한 것은 무엇입니까? 몇 주 동안 테스트를 추가하거나 몇 주 동안 기능을 추가합니까?
(분명히 세 번째 요점에 대한 답변은 전적으로 관리자 또는 개발자와 대화하고 있는지 여부에 달려 있습니다)
현상금에 대한 이유
현상금을 추가하여 기존의 의심을 확인하는 것뿐만 아니라 수행해야 할 좋은 이유를 확인하는 더 넓은 범위의 답변을 시도하고 유치하려고합니다.
이 장을 나중에 장단점으로 작성하여 경영진에게 제품의 미래 개발을 TDD로 옮기는 데 시간을 투자 할 가치가 있음을 보여 주려고 노력하고 있습니다. 나는이 도전에 접근하고 편견없이 자신의 추론을 발전 시키려고합니다.
이전에는 없었던 코드 기반에 단위 테스트를 도입했습니다. 내가이 작업을 수행 한 마지막 큰 프로젝트는 팀에 도착했을 때 제품 테스트가없는 상태에서 이미 생산되었습니다. 내가 2 년 후에 떠났을 때, 우리는 4500+ 정도의 테스트를 거쳐 230 000 + 프로덕션 LOC (실시간 금융 Win-Forms 응용 프로그램)가 포함 된 코드베이스에서 약 33 %의 코드 커버리지를 산출했습니다. 저음으로 들릴지 모르지만 결과적으로 코드 품질과 결함률이 크게 향상되어 사기와 수익성이 향상되었습니다.
관련 당사자의 정확한 이해와 약속이있을 때 수행 할 수 있습니다.
우선, 단위 테스트는 그 자체가 기술이라는 것을 이해하는 것이 중요합니다. "전통적인"표준으로 생산성이 높은 프로그래머가 되더라도 더 큰 프로젝트에서 확장되는 방식으로 단위 테스트를 작성하는 데 어려움을 겪을 수 있습니다.
또한 특히 상황에 따라 테스트가없는 기존 코드베이스에 단위 테스트를 추가하는 것도 전문 기술입니다. 귀하 또는 귀하의 팀원이 기존 코드베이스에 단위 테스트를 도입 한 경험이 없다면, Feather 's book을 읽는 것이 필수입니다 (선택적이거나 강력하게 권장되지 않음).
코드 단위 테스트로 전환하는 것은 코드 기반의 품질만큼이나 사람과 기술에 대한 투자입니다. 이를 이해하는 것은 사고 방식과 기대 관리 측면에서 매우 중요합니다.
귀하의 의견과 질문에 대해 :
그러나 나는 큰 그림을 잃어 버리고 결국 TDD를 사용하면 포함 된 기본 테스트가 누락 될까 걱정하고 있습니다.
짧은 대답 : 그렇습니다. 테스트를 놓치면 처음에는 그린 필드 상황에서와 똑같이 보이지 않을 수 있습니다.
더 깊은 수준의 대답은 이것입니다 : 그것은 중요하지 않습니다. 테스트없이 시작하십시오. 테스트 추가를 시작하고 진행하면서 리팩터링하십시오. 기술 수준이 향상되면 프로젝트에 추가 된 모든 새로 작성된 코드에 대한 기준을 높이십시오. 계속 개선하십시오 ...
자, 여기서 줄 사이를 읽으면서 이것이 "행동을 취하지 않는 변명"으로서의 생각에서 온다는 인상을받습니다. 더 나은 사고 방식은 자기 신뢰에 집중하는 것입니다. 어떻게해야할지 아직 모를 수 있으므로 빈칸을 채우고 채울 때 어떻게해야하는지 알아낼 것입니다. 따라서 걱정할 이유가 없습니다.
다시, 그 기술. 선형 방식으로 하나의 "프로세스"또는 "단계별"쿡 북 접근 방식으로 제로 테스트에서 TDD- 완벽으로 이동할 수 없습니다. 과정이 될 것입니다. 점진적이고 점진적인 진전과 개선을 기대해야합니다. 마법의 약은 없습니다.
좋은 소식은 몇 개월 (그리고 몇 년)이지나면서 코드가 점차 "적절하게"잘 인수되고 테스트 된 코드가되기 시작한다는 것입니다.
부수적으로. 오래된 코드 기반에서 단위 테스트를 도입하는 데있어 주요 장애물은 응집력과 과도한 종속성이 없다는 것입니다. 따라서 가장 중요한 기술은 실제 단위 테스트 자체를 작성하지 않고 기존 종속성을 분리하고 코드를 분리하는 방법이 될 것입니다.
기존 솔루션이 제대로 단위 테스트를 거치지 않고 제대로 테스트되도록하기 위해 준수해야하는 프로세스 / 단계가 있습니까?
아직 설치하지 않은 경우 빌드 서버를 설정하고 코드 적용 범위가있는 모든 단위 테스트를 포함하여 모든 체크인에서 실행되는 연속 통합 빌드를 설정하십시오.
사람들을 훈련 시키십시오.
고객의 관점에서 진행하면서 어딘가에서 시작하여 테스트를 추가하십시오 (아래 참조).
테스트중인 프로덕션 코드베이스의 양에 대한 지침으로 코드 적용 범위를 사용하십시오.
빌드 시간은 항상 빠릅니다. 빌드 시간이 느리면 단위 테스트 기술이 지연됩니다. 느린 테스트를 찾아서 개선하십시오 (제작 코드 분리 및 격리 테스트). 잘 작성하면 쉽게 수천 단위의 단위 테스트를 수행하고 10 분 이내에 빌드를 완료 할 수 있어야합니다 (~ 1 ms / 테스트는 좋지만 매우 거친 지침입니다. 반복을 사용하는 코드와 같은 예외는 거의 없습니다. ).
검사하고 적응하십시오.
테스트 품질이 좋고 테스트가 아닌 테스트가 테스트가 아닌 것보다 낫다는 것을 어떻게 확인할 수 있습니까?
당신 자신의 판단은 당신의 주요 현실의 근원이어야합니다. 스킬을 대체 할 수있는 메트릭이 없습니다.
그 경험이나 판단력이 없다면, 계약을 맺은 사람과 계약을 고려하십시오.
2 개의 대략적인 2 차 지표는 총 코드 적용 범위와 빌드 속도입니다.
프로덕션 환경에있는 기존 솔루션에 대한 노력의 가치가 있습니까?
예. 맞춤형 시스템 또는 솔루션에 소비되는 대부분의 돈은 생산 후 투입됩니다. 그리고 품질, 사람 및 기술에 대한 투자는 결코 스타일을 벗어나서는 안됩니다.
이 프로젝트의 테스트를 무시하고 나중에 다시 작성할 수 있도록 추가하는 것이 더 좋습니까?
사람과 기술에 대한 투자뿐만 아니라 총 소유 비용과 시스템의 예상 수명 시간을 고려해야합니다.
제 개인의 대답은 대부분의 경우 "물론 예"가 될 것입니다. 왜냐하면 나는 그 점을 훨씬 더 잘 알고 있기 때문에 예외가 있다는 것을 알고 있습니다.
더 유익한 것은 무엇입니까? 몇 주 동안 테스트를 추가하거나 몇 주 동안 기능을 추가합니까?
둘 다. 기능 측면에서 진보하는 동안 코드 기반에 테스트를 추가해야합니다.
다시 말하지만 사람, 기술 및 코드 기반의 품질에 대한 투자이므로 시간이 필요합니다. 팀 구성원은 종속성을 깨고, 단위 테스트를 작성하고, 새로운 습관을 배우고, 훈련 및 품질 인식을 개선하고, 소프트웨어를 더 잘 디자인하는 방법 등을 배워야합니다. 테스트를 추가 할 때 팀원이 그렇지 않을 가능성을 이해하는 것이 중요합니다 이러한 기술을 사용하는 데 필요한 수준의 기술을 보유하고 있기 때문에 많은 테스트를 추가하기 위해 모든 시간을 소비하기 위해 진행을 중단하는 것은 효과가 없습니다.
또한 규모가 큰 프로젝트 크기의 기존 코드베이스에 단위 테스트를 추가하는 것은 약속과 지속성이 필요한 대규모 사업입니다. 근본적인 것을 바꿀 수 없으며, 많은 학습을 기대하고 스폰서에게 비즈니스 가치 흐름을 중단하여 ROI를 기대하지 않도록 요청할 수 없습니다. 그것은 날지 않을 것이고, 솔직히 말하면 안됩니다.
셋째, 팀에 건전한 비즈니스 포커스 가치를 부여하고자합니다. 품질은 고객을 희생하지 않으며 품질 없이는 빨리 갈 수 없습니다. 또한 고객은 변화하는 세상에 살고 있으며 귀하의 업무는 고객이보다 쉽게 적응할 수 있도록하는 것입니다. 고객 맞춤에는 품질과 비즈니스 가치 흐름이 모두 필요합니다.
당신이하고있는 일은 기술 부채를 지불하는 것입니다. 그리고 계속해서 변화하는 요구에 고객에게 서비스를 제공하면서 그렇게하고 있습니다. 점차 부채가 상환되면 상황이 개선되며 고객에게 더 나은 서비스를 제공하고 더 많은 가치를 제공하는 것이 더 쉽습니다. 기타이 긍정적 인 추진력은 지속 가능한 페이스의 원칙에 밑줄을 긋고 개발 팀, 고객 및 이해 관계자 모두에게 도덕을 유지하고 향상 시키므로 목표로 삼아야합니다.
희망이 도움이
- 프로덕션 환경에있는 기존 솔루션에 대한 노력의 가치가 있습니까?
예!
- 이 프로젝트의 테스트를 무시하고 나중에 다시 작성할 수 있도록 추가하는 것이 더 좋습니까?
아니!
- 더 유익한 것은 무엇입니까? 몇 주 동안 테스트를 추가하거나 몇 주 동안 기능을 추가합니까?
테스트 (특히 자동 테스트)를 추가 하면 향후 프로젝트를 훨씬 쉽게 유지할 수 있으며 사용자에게 어리석은 문제가 발생할 가능성이 크게 줄어 듭니다.
우선 순위 에 넣는 테스트 는 코드에 대한 공용 인터페이스 (및 각 모듈)가 생각하는 방식으로 작동하는지 여부를 확인 하는 테스트 입니다. 가능하면 코드 모듈에 포함 된 각각의 분리 된 실패 모드를 유도하십시오 (이것은 사소하지 않을 수 있으며 실제로 실패하지 않는 방식을주의 깊게 검사하지 않도록주의해야합니다) 로그 기록이 충분한 지 확인하기 때문에 실패시 생성되는 로그 메시지 수 계산과 같은 작업을 수행합니다.
그런 다음 버그 데이터베이스에있는 현재 버그 각각에 대해 테스트하여 버그를 정확하게 유도하고 버그가 수정되면 통과합니다. 그런 다음 그 버그를 수정하십시오! :-)
테스트를 추가하는 데 시간이 오래 걸리지 만 코드 품질이 훨씬 높아짐에 따라 백엔드에서 여러 번 상환됩니다. 새 버전을 배송하거나 유지 보수를 수행 할 때 매우 중요합니다.
개량 단위 테스트의 문제점은 여기서 의존성을 주입하거나 인터페이스를 사용하지 않았다는 사실을 깨닫게되며 얼마 지나지 않아 전체 구성 요소를 다시 작성하게됩니다. 이 작업을 수행 할 시간이 있다면 멋진 안전망을 구축 할 수 있지만 그 과정에서 미묘한 버그가 발생할 수 있습니다.
나는 처음부터 단위 테스트가 실제로 필요한 많은 프로젝트에 참여했으며, 코드를 작성하고 이미 돈을 벌 때 일반적으로 정당화 할 수없는 완전한 재 작성이 부족한 쉬운 방법이 없습니다. 최근에는 결함이 발생하자마자 재생산하는 방식으로 코드를 실행하는 powershell 스크립트를 작성하고 이러한 스크립트를 추가 변경을위한 회귀 테스트 모음으로 유지했습니다. 이렇게하면 응용 프로그램에 대한 테스트를 너무 많이 변경하지 않고도 최소한 일부 테스트를 작성할 수 있지만 적절한 단위 테스트보다 종단 간 회귀 테스트와 비슷합니다.
나는 대부분의 다른 사람들이 말한 것에 동의합니다. 기존 코드에 테스트를 추가하는 것이 중요합니다. 나는 그 점에 동의하지 않을 것이지만 하나의 경고를 추가하고 싶습니다.
기존 코드에 테스트를 추가하는 것은 가치가 있지만 비용이 많이 듭니다. 새로운 기능을 구축 하지 않으면 비용이 발생 합니다. 이 두 가지의 균형을 맞추는 방법은 전적으로 프로젝트에 달려 있으며 여러 변수가 있습니다.
- 모든 코드를 테스트하는 데 얼마나 걸립니까? 일? 몇 주? 몇 달? 연령?
- 이 코드를 누가 작성하고 있습니까? 고객 지불? 교수? 오픈 소스 프로젝트?
- 일정은 어떻습니까? 충족해야 할 마감일이 있습니까? 마감일이 있습니까?
다시 강조하겠습니다. 테스트는 가치가 있으며 이전 코드를 테스트하기 위해 노력해야합니다. 이것은 실제로 어떻게 접근하는지에 대한 문제입니다. 모든 것을 버리고 이전 코드를 모두 테스트 할 여유가 있다면 그렇게하십시오. 그것이 현실적이지 않다면, 최소한 여기에해야 할 일이 있습니다.
- 작성하는 모든 새 코드는 완전히 단위 테스트를 받아야합니다
- 만지는 오래된 코드 (버그 수정, 확장 프로그램 등)는 단위 테스트를 거쳐야합니다.
또한 이것은 전부가 아닌 제안이 아닙니다. 예를 들어 4 명으로 구성된 팀이 있고 1 ~ 2 명을 레거시 테스트 의무에 맡겨 마감일을 맞출 수 있다면 반드시 그렇게하십시오.
편집하다:
이 장을 나중에 장단점으로 작성하여 경영진에게 제품의 미래 개발을 TDD로 옮기는 데 시간을 투자 할 가치가 있음을 보여 주려고 노력하고 있습니다.
"소스 제어 사용의 장단점은 무엇입니까?" 또는 "채용하기 전에 사람들을 인터뷰 할 때의 장단점은 무엇입니까?" 또는 "호흡의 장단점은 무엇입니까?"
때로는 논쟁의 한 면만 있습니다. 복잡한 프로젝트에 대해 어떤 형태의 자동화 된 테스트가 필요합니다. 아니요, 테스트는 자체적으로 작성되지 않으며, 문제를 해결하는 데 약간의 시간이 더 걸립니다. 그러나 장기적으로는 테스트를 미리 작성하는 것보다 버그를 수정하는 데 더 많은 시간과 비용이 소요됩니다. 기간. 그것이 전부입니다.
테스트를 추가하기 시작했을 때, UI와보고 코드에 너무 많은 로직을 가진 10 년 된 약 백만 라인 코드베이스였습니다.
연속 빌드 서버를 설정 한 후 처음으로 한 작업 중 하나는 회귀 테스트를 추가하는 것이 었습니다. 이것들은 엔드-투-엔드 테스트였습니다.
- 각 테스트 스위트는 데이터베이스를 알려진 상태로 초기화하여 시작합니다. 실제로 Subversion에 보관하는 수십 개의 회귀 데이터 세트가 있습니다 (순서 크기 때문에 코드와 별도의 저장소에 있음). 각 테스트의 FixtureSetUp은 이러한 회귀 데이터 세트 중 하나를 임시 데이터베이스에 복사 한 다음 거기에서 실행됩니다.
- 그런 다음 테스트 픽스처 설정은 결과에 관심이있는 일부 프로세스를 실행합니다.이 단계는 선택 사항입니다. 일부 회귀 테스트는 보고서를 테스트하기 위해서만 존재합니다.
- 그런 다음 각 테스트는 보고서를 실행하고 보고서를 .csv 파일로 출력 한 다음 해당 .csv의 내용을 저장된 스냅 샷과 비교합니다. 이 스냅 샷 .csvs는 각 회귀 데이터 세트 옆의 Subversion에 저장됩니다. 보고서 출력이 저장된 스냅 샷과 일치하지 않으면 테스트가 실패합니다.
회귀 테스트의 목적은 변경 사항이 있는지 알려주는 것입니다. 즉, 문제가 발생하면 실패하지만 의도적으로 무언가를 변경하면 실패합니다 (이 경우 수정은 스냅 샷 파일을 업데이트하는 것임). 스냅 샷 파일이 올바른지조차 모릅니다. 시스템에 버그가있을 수 있습니다 (그런 다음 버그를 수정하면 회귀 테스트가 실패합니다).
그럼에도 불구하고 회귀 테스트는 우리에게 큰 승리였습니다. 우리 시스템의 거의 모든 것이 보고서를 가지고 있기 때문에 보고서 주위에서 테스트 하네스를 얻는 데 몇 주를 소비함으로써 우리는 코드 기반의 상당 부분을 어느 정도 커버 할 수있었습니다. 동등한 단위 테스트를 작성하는 데 몇 개월 또는 몇 년이 걸렸습니다. (단위 테스트는 우리에게 훨씬 더 나은 적용 범위를 제공했을 것이고 훨씬 덜 취약했을 것입니다. 그러나 나는 완벽을 위해 몇 년을 기다리는 대신 지금 무언가를 갖고 싶습니다.)
그런 다음 버그를 수정하거나 개선 사항을 추가하거나 일부 코드를 이해해야 할 때 단위 테스트를 추가하기 시작했습니다. 회귀 테스트는 결코 단위 테스트의 필요성을 제거하지 않습니다. 그것들은 단지 첫 번째 수준의 안전망이므로 어느 정도의 테스트 범위를 빠르게 얻을 수 있습니다. 그런 다음 리팩토링을 시작하여 종속성을 깨뜨릴 수 있으므로 단위 테스트를 추가 할 수 있습니다. 회귀 테스트를 통해 리팩토링으로 인해 아무런 문제가 발생하지 않는다는 확신을 얻을 수 있습니다.
회귀 테스트에는 문제가 있습니다. 속도가 느리고 깨질 수있는 이유가 너무 많습니다. 그러나 우리를 위해 적어도 그들은했다 그래서 가치. 지난 5 년 동안 수많은 버그를 발견했으며 QA주기를 기다리는 대신 몇 시간 내에 버그를 발견했습니다. 우리는 여전히 그 원래의 회귀 테스트를 가지고 있으며, 빠른 연속 테스트를 수행하는 것과는 다른 7 개의 연속 빌드 머신에 분산되어 있으며, 우리는 여전히 6,000 코드를 너무 많이 사용하기 때문에 때때로 추가합니다. + 단위 테스트는 다루지 않습니다.
그만한 가치가 있습니다. 앱에 복잡한 교차 유효성 검사 규칙이 있으며 최근 비즈니스 규칙을 크게 변경해야했습니다. 결국 사용자가 저장하지 못하게하는 충돌이 발생했습니다. 나는 applcation에서 그것을 분류하는 데 영원히 걸릴 것이라고 깨달았습니다 (문제가 발생한 지점까지 도달하는 데 몇 분이 걸립니다). 자동화 된 단위 테스트를 도입하고 프레임 워크를 설치하고 싶었지만, 몇 가지 더미 테스트 외에는 아무런 작업도 수행하지 않았습니다. 새로운 비즈니스 규칙에 따라 테스트를 시작했습니다. 테스트를 통해 충돌을 일으킨 조건을 신속하게 파악하고 규칙을 명확하게 파악할 수있었습니다.
추가하거나 수정하는 기능을 다루는 테스트를 작성하면 즉각적인 이점이 있습니다. 다시 쓰기를 기다리는 경우 자동 테스트가 없을 수 있습니다.
이미 작동하는 기존 항목에 대한 테스트를 작성하는 데 많은 시간을 소비해서는 안됩니다. 대부분의 경우 기존 코드에 대한 사양이 없으므로 테스트하려는 주요 사항은 리버스 엔지니어링 기능입니다. 반면에 무언가를 수정하려는 경우 해당 기능을 테스트로 다루어야 변경 사항이 올바르게 적용되었음을 알 수 있습니다. 물론 새로운 기능의 경우 실패한 테스트를 작성한 다음 누락 된 기능을 구현하십시오.
음성을 추가하고 예라고 말하면 항상 유용합니다!
그러나 블랙 박스와 화이트 박스, 그리고 유닛과 기능에 대한 몇 가지 차이점을 명심해야합니다. 정의가 다양하기 때문에 다음과 같은 의미를 갖습니다.
- 블랙 박스 (Black-box) = 구현에 대한 특별한 지식없이 작성된 테스트. 일반적으로 순진한 사용자가 예상 한대로 일이 발생하는지 확인하기 위해 에지 케이스를 검색합니다.
- 화이트 박스는 기록 된 테스트 = 로 종종 잘 알려진 장애 지점을 행사하려고 구현, 지식.
- 단위 테스트 = 개별 단위 (기능, 분리 가능 모듈 등)의 테스트 예를 들어, 배열 클래스가 예상대로 작동하고 문자열 비교 함수가 광범위한 입력에 대해 예상 된 결과를 반환하는지 확인하십시오.
- 기능 테스트 = 한 번에 전체 시스템을 테스트합니다. 이 테스트는 한 번에 시스템의 큰 덩어리를 시험합니다. 예를 들어 : 초기화, 연결 열기, 실제 작업 수행, 종료, 종료. 나는 이것들과 단위 테스트가 다른 목적을 제공하기 때문에 구별하기를 좋아합니다.
게임 후반에 배송 제품에 테스트를 추가했을 때 화이트 박스 및 기능 테스트 에서 가장 많은 비용을 지불했습니다 . 특히 취약한 코드 부분이 있으면 문제를 해결하기 위해 화이트 박스 테스트를 작성하여 같은 방식으로 두 번 깨지지 않도록하십시오. 마찬가지로 전체 시스템 기능 테스트는 가장 일반적인 10 가지 사용 사례를 위반하지 않도록하는 유용한 온 전성 검사입니다.
작은 단위의 블랙 박스 및 단위 테스트도 유용하지만 시간이 제한되어 있으면 조기에 추가하는 것이 좋습니다. 배송 할 때 일반적으로 이러한 테스트에서 발견 된 대부분의 엣지 사례와 문제를 발견했습니다.
다른 사람들과 마찬가지로 TDD에 대해 가장 중요한 두 가지 사항을 상기시켜 드리겠습니다.
- 테스트 작성은 지속적인 작업입니다. 절대 멈추지 않습니다. 새 코드를 작성하거나 기존 코드를 수정할 때마다 새 테스트를 추가해야합니다.
- 테스트 스위트는 절대 완벽하지 않습니다! 테스트를 받았다는 사실로 인해 잘못된 보안 감각을 느끼게하지 마십시오. 테스트 스위트를 통과했다고해서 그것이 올바르게 작동하거나 미묘한 성능 회귀 등을 도입하지 않았다는 의미는 아닙니다.
프로덕션 환경에있는 앱에 단위 테스트를 추가 할 가치가 있는지 여부는 앱 유지 관리 비용에 따라 다릅니다. 앱에 버그와 개선 요청이 거의 없다면 노력할 가치가 없을 것입니다. OTOH, 앱이 버그가 있거나 자주 수정되면 단위 테스트가 큰 도움이 될 것입니다.
이 시점에서 단위 테스트를 선택적으로 추가하는 것에 대해 이야기하고 있음을 기억하십시오. 처음부터 TDD를 연습했을 때 존재할 테스트와 유사한 테스트 세트를 생성하려고 시도하지 마십시오. 따라서, 두 번째 질문의 후반 님의 질문에 답변이 새 프로젝트 또는 다시 쓰기 (사과가,인지, 당신의 다음 프로젝트에 TDD를 사용하는 점을 그러나 여기에 대한 링크입니다 다른 당신이 정말로 읽어야 책 : 테스트에 따라 성장하는 객체 지향 소프트웨어 )
세 번째 질문에 대한 나의 대답은 첫 번째 질문과 동일합니다. 프로젝트의 상황에 따라 다릅니다.
게시물에 포함 된 내용은 개조 된 테스트가 올바르게 수행 되는지에 대한 추가 질문 입니다. 확인해야 할 중요한 점은 단위 테스트가 실제로 단위 테스트라는 것입니다. 이는 개량 테스트에서 기존 코드를 리팩터링하여 레이어 / 컴포넌트의 디커플링을 허용해야한다는 것을 의미합니다 (종속성 주입; 제어 역전; 스터 빙; 조롱). 이를 시행하지 않으면 테스트가 통합 테스트가되어 실제 단위 테스트보다 유용하지만 덜 대상이되고 취성이 적습니다.
구현 언어에 대해서는 언급하지 않지만 Java 인 경우 다음 방법을 시도 할 수 있습니다.
별도의 소스 트리 빌드 회귀 또는 '연기'테스트에서이를 생성하는 도구를 사용하면 80 %에 근접 할 수 있습니다. 이 테스트는 모든 코드 논리 경로를 실행하고 그 시점부터 코드가 여전히 현재 수행중인 작업을 정확히 수행하는지 확인합니다 (버그가있는 경우에도). 이를 통해 필요한 리팩토링을 수행 할 때 실수로 변경되는 동작에 대한 안전망을 제공하여 손으로 코드를 쉽게 테스트 할 수 있습니다.
- 제품 제안-무료 웹 기반 제품 Junit Factory를 사용했지만 슬프게도 마감되었습니다. 그러나이 제품은 http://www.agitar.com/solutions/products/automated_junit_generation.html 의 상용 라이센스 AgitarOne JUnit 생성기에서 작동합니다 .
수정 한 버그 또는 지금부터 추가 한 기능에 대해 TDD 접근 방식을 사용하여 새 코드를 테스트 할 수 있도록 설계하고 이러한 테스트를 일반 테스트 소스 트리에 배치하십시오.
기존 코드도 새로운 기능을 추가하는 과정에서 테스트 할 수 있도록 변경하거나 리팩토링해야합니다. 연기 테스트는 회귀 또는 의도하지 않은 미묘한 행동 변화에 대한 안전망을 제공합니다.
TDD를 통해 변경 (버그 수정 또는 기능)을 수행 할 때 완료되면 동반 연기 테스트가 실패했을 수 있습니다. 손으로 쓴 단위 테스트에서 개선 된 구성 요소를 완벽하게 다루기 때문에 변경 사항으로 인해 오류가 예상대로 확인되고 읽기 어려운 연기 테스트가 제거됩니다. 테스트 범위가 줄어들지 않아야합니다.
버그를 수정하는 경우 먼저 버그를 노출시키는 실패한 단위 테스트를 작성하십시오.
단위 테스트는 버그가 생산에 들어가기 전에 체포하는 데 도움이되므로 단위 테스트가 정말 중요하다고 말하면서이 답변을 시작하고 싶습니다.
버그가 재 도입 된 프로젝트 / 모듈 영역을 식별하십시오. 프로젝트를 시작하여 테스트를 작성하십시오. 새로운 기능과 버그 수정에 대한 테스트를 작성하는 것이 완벽합니다.
프로덕션 환경에있는 기존 솔루션에 대한 노력의 가치가 있습니까?
예. 버그가 줄어들고 유지 관리가 쉬워지는 효과를 볼 수 있습니다
이 프로젝트의 테스트를 무시하고 나중에 다시 작성할 수 있도록 추가하는 것이 더 좋습니까?
지금부터 시작하는 것이 좋습니다.
더 유익한 것은 무엇입니까? 몇 주 동안 테스트를 추가하거나 몇 주 동안 기능을 추가합니까?
당신은 잘못된 질문을하고 있습니다. 확실히, 기능은 다른 무엇보다 중요합니다. 그러나 테스트를 추가하는 데 몇 주가 걸리면 내 시스템이 더 안정적 일지 묻습니다. 이것이 최종 사용자에게 도움이됩니까? 팀의 새로운 개발자가 프로젝트를 이해하고 변경의 전반적인 영향에 대한 이해 부족으로 인해 버그가 발생하지 않도록하는 데 도움이됩니까?
리팩토링을 시작할 위치에 대한 답으로 로우 행잉 과일 리팩터링을 매우 좋아 합니다. 씹을 수있는 것 이상으로 물지 않고 더 나은 디자인으로 편하게 할 수있는 방법입니다.
동일한 논리가 TDD 또는 단위 테스트에만 적용된다고 생각합니다. 필요한 테스트를 필요한대로 작성하십시오. 새로운 코드에 대한 테스트 작성; 버그가 나타날 때 테스트를 작성하십시오. 코드베이스의 접근하기 어려운 영역을 무시하는 것에 대해 걱정하고 있으며 위험하지만 시작하는 방법으로 시작하십시오! 코드 커버리지 도구를 사용하여 위험을 완화시킬 수 있으며, 어쨌든 그 위험은 크지 않습니다. 버그를 다루고 있다면 새 코드를 다루고 있으며 찾고있는 코드를 덮고 있습니다 테스트가 가장 필요한 코드를 다루고 있습니다.
- 그렇습니다. 새로운 기능 추가를 시작하면 오래된 코드가 수정 될 수 있으며 결과적으로 잠재적 인 버그의 원인이됩니다.
- 새로운 기능을 추가하기 전에 (첫 번째 코드 참조) 모든 (또는 거의) 코드는 (이상적으로는) 단위 테스트에 의해 커버되어야합니다.
- (첫 번째와 두 번째 참조) :). 새로운 장대 한 기능은 이전에 작동했던 코드를 "파기"할 수 있습니다.
예, 가능합니다. 이제 작성한 모든 코드에 테스트가 있는지 확인하십시오.
이미 존재하는 코드를 수정하고 테스트 할 수 있어야한다면 그렇게해야하지만 안정적인 코드를위한 테스트를 시도하는 데 너무 힘이없는 것이 좋습니다. 이런 종류의 물건은 노크 효과가 있고 통제 불능 상태가 될 수 있습니다.
프로덕션 환경에있는 기존 솔루션에 대한 노력의 가치가 있습니까?예. 그러나 시작하기 위해 모든 단위 테스트를 작성할 필요는 없습니다. 하나씩 추가하십시오.
이 프로젝트의 테스트를 무시하고 나중에 다시 작성할 수 있도록 추가하는 것이 더 좋습니까?아니요. 기능을 손상시키는 코드를 처음 추가하면 후회하게됩니다.
더 유익한 것은 무엇입니까? 몇 주 동안 테스트를 추가하거나 몇 주 동안 기능을 추가합니까?새로운 기능 (코드)의 경우 간단합니다. 먼저 단위 테스트를 작성한 다음 기능을 작성하십시오. 오래된 코드의 경우 길을 결정합니다. 모든 단위 테스트를 시행 할 필요는 없습니다 ... 가장 많이 해치지 않은 테스트를 추가하십시오 ... 시간 (및 오류)은 어느 것을 집중해야하는지 알려줍니다.)
최신 정보
원래 답변 후 6 년이 조금 걸립니다.
여러분이 작성한 모든 새로운 코드에 단위 테스트를 추가 한 다음 테스트 할 수 있도록 변경 한 위치를 리팩터링하는 것이 합리적이라고 생각합니다.
Writing tests in one go for all your existing code will not help - but not writing tests for new code you write (or areas you modify) also doesn't make sense. Adding tests as you refactor/add things is probably the best way to add tests and make the code more maintainable in an existing project with no tests.
Earlier answer
Im going to raise a few eyebrows here :)
First of all what is your project - if it is a compiler or a language or a framework or anything else that is not going to change functionally for a long time, then I think its absolutely fantastic to add unit tests.
However, if you are working on an application that is probably going to require changes in functionality (because of changing requirements) then there is no point in taking that extra effort.
Why?
Unit tests only cover code tests - whether the code does what it is designed to - it is not a replacement for manual testing which anyways has to be done (to uncover functional bugs, usability issues and all other kinds of issues)
Unit tests cost time! Now where I come from, that's a precious commodity - and business generally picks better functionality over a complete test suite.
If your application is even remotely useful to users, they are going to request changes - so you will have versions that will do things better, faster and probably do new things - there may also be a lot of refactoring as your code grows. Maintaining a full grown unit test suite in a dynamic environment is a headache.
Unit tests are not going to affect the perceived quality of your product - the quality that the user sees. Sure, your methods might work exactly as they did on day 1, the interface between presentation layer and business layer might be pristine - but guess what? The user does not care! Get some real testers to test your application. And more often than not, those methods and interfaces have to change anyways, sooner or later.
What will be more benefical; spending a few weeks adding tests or a few weeks adding functionality? - There are hell lot of things that you can do better than writing tests - Write new functionality, improve performance, improve usability, write better help manuals, resolve pending bugs, etc etc.
Now dont get me wrong - If you are absolutely positive that things are not going to change for next 100 years, go ahead, knock yourself out and write those tests. Automated Tests are a great idea for APIs as well, where you absolutely do not want to break third party code. Everywhere else, its just something that makes me ship later!
It's unlikely you'll ever have significant test coverage, so you must be tactical about where you add tests:
- As you mentioned, when you find a bug, it's a good time to write a test (to reproduce it), and then fix the bug. If you see the test reproduce the bug, you can be sure it's a good, alid test. Given such a large portion of bugs are regressions (50%?), it's almost always worth writing regression tests.
- When you dive into an area of code to modify it, it's a good time to write tests around it. Depending on the nature of the code, different tests are appropriate. One good set of advice is found here.
OTOH, it's not worth just sitting around writing tests around code that people are happy with-- especially if nobody is going to modify it. It just doesn't add value (except maybe understanding the behavior of the system).
Good luck!
You say you don't want to buy another book. So just read Michael Feather's article on working effectively with legacy code. Then buy the book :)
If I were in your place, I would probably take an outside-in approach, starting with functional tests that exercise the whole system. I would try to re-document the system's requirements using a BDD specification language like RSpec, and then write tests to verify those requirements by automating the user interface.
Then I would do defect driven development for newly discovered bugs, writing unit tests to reproduce the problems, and work on the bugs until the tests pass.
For new features, I would stick with the outside-in approach: Start with features documented in RSpec and verified by automating the user interface (which will of course fail initially), then add more finely-grained unit tests as the implementation moves along.
I'm no expert on the process, but from what little experience I have I can tell you that BDD via automated UI testing is not easy, but I think it's worth the effort, and probably would yield the most benefit in your case.
I'm not a seasoned TDD expert by any means, but of course I would say that it's incredibly important to unit test as much as you can. Since the code is already in place, I would start by getting some sort of unit test automation in place. I use TeamCity to exercise all of the tests in my projects, and it gives you a nice summary of how the components did.
With that in place, I'd move on to those really critical business logic-like components that can't fail. In my case, there are some basic trigometry problems that need to be solved for various inputs, so I test the heck out of those. The reason I do this is that when I'm burning the midnight oil, it's very easy to waste time digging down to depths of code that really don't need to be touched, because you know they are tested for all of the possible inputs (in my case, there is a finite number of inputs).
Ok, so now you hopefully feel better about those critical pieces. Instead of sitting down and banging out all of the tests, I would attack them as they come up. If you hit a bug that's a real PITA to fix, write the unit tests for it and get them out of the way.
There are cases where you'll find that testing is tough because you can't instantiate a particular class from the test, so you have to mock it. Oh, but maybe you can't mock it easily because you didn't write to an interface. I take these "whoops" scenarios as an opportunity to implement said interface, because, well, it's a Good Thing.
From there, I'd get your build server or whatever automation you have in place configured with a code coverage tool. They create nasty bar graphs with big red zones where you have poor coverage. Now 100% coverage isn't your goal, nor would 100% coverage necessarily mean your code is bulletproof, but the red bar definitely motivates me when I have free time. :)
There is so many good answers so I will not repeat their content. I checked your profile and it seems you are C# .NET developer. Because of that I'm adding reference to Microsoft PEX and Moles project which can help you with autogenerating unit tests for legacy code. I know that autogeneration is not the best way but at least it is the way to start. Check this very interesting article from MSDN magazine about using PEX for legacy code.
I suggest reading a brilliant article by a TopTal Engineer, that explains where to start adding tests: it contains a lot of maths, but the basic idea is:
1) Measure your code's Afferent Coupling (CA) (how much a class is used by other classes, meaning breaking it would cause widespread damage)
2) Measure your code's Cyclomatic Complexity (CC) (higher complexity = higher change of breaking)
You need to identify classes with high CA and CC, i.e. have a function f(CA,CC) and the classes with the smallest differences between the two metrics should be given the highest priority for test coverage.
Why? Because a high CA but very low CC classes are very important but unlikely to break. On the other hand, low CA but high CC are likely to break, but will cause less damage. So you want to balance.
It depends...
It's great to have unit tests but you need to consider who your users are and what they are willing to tolerate in order to get a more bug-free product. Inevitably by refactoring your code which has no unit tests at present, you will introduce bugs and many users will find it hard to understand that you are making the product temporarily more defective to make it less defective in the long run. Ultimately it's the users who will have the final say...
Yes. No. Adding tests.
Going towards a more TDD approach will actually better inform your efforts to add new functionality and make regression testing much easier. Check it out!
'development' 카테고리의 다른 글
서비스를 시작한 후 Docker 컨테이너를 계속 실행하는 방법은 무엇입니까? (0) | 2020.07.01 |
---|---|
Java에서 문자열을 암호화하는 방법 (0) | 2020.06.30 |
SDF 파일을 어떻게 열 수 있습니까 (SQL Server Compact Edition)? (0) | 2020.06.30 |
일련의 jQuery 연기로 어떻게 작업합니까? (0) | 2020.06.30 |
변수가 설정되지 않은 경우 makefile 중단 (0) | 2020.06.30 |