단위 테스트 C ++ : 테스트 대상


20

TL; DR

훌륭하고 유용한 테스트를 작성하는 것은 어렵고 C ++에서는 비용이 많이 듭니다. 숙련 된 개발자가 무엇을 언제 테스트해야하는지에 대한 이론적 근거를 공유 할 수 있습니까?

긴 이야기

실제로 팀 전체에서 테스트 중심 개발을 수행했지만 실제로는 효과가 없었습니다. 우리는 많은 테스트를 가지고 있지만 실제 버그와 회귀가있는 경우를 다루지 않는 것 같습니다. 일반적으로 장치가 고립 된 행동이 아닌 상호 작용할 때 발생합니다.

이것은 종종 단위 수준에서 테스트하기가 어렵 기 때문에 TDD 수행을 중단하고 (실제로 개발 속도를 높이는 구성 요소 제외) 통합 테스트 범위를 늘리는 데 더 많은 시간을 투자했습니다. 소규모 단위 테스트에서는 실제 버그가 발생하지 않았으며 기본적으로 유지 관리 오버 헤드 만 있었지만 통합 테스트는 실제로 그만한 가치가있었습니다.

이제 새 프로젝트를 상속했으며 테스트 방법에 대해 궁금합니다. 네이티브 C ++ / OpenGL 응용 프로그램이므로 통합 테스트는 실제로 옵션이 아닙니다. 그러나 C ++의 단위 테스트는 Java보다 약간 어렵습니다 (명시 적으로 물건을 만들어야합니다 virtual). 프로그램은 객체 지향적이지 않으므로 물건을 모방 / 스터브 할 수 없습니다.

테스트 작성을 위해 테스트를 작성하기 위해 모든 것을 분리하고 OO-ize하고 싶지 않습니다. 그래서 나는 당신에게 묻습니다 : 무엇을 테스트해야합니까? 예 :

  • 자주 변경되는 함수 / 클래스?
  • 수동으로 테스트하기 어려운 함수 / 클래스?
  • 이미 테스트하기 쉬운 함수 / 클래스?

나는 존경받는 C ++ 코드베이스를 조사하여 테스트 방법에 대해 알아보기 시작했습니다. 현재 Chromium 소스 코드를 살펴보고 있지만 코드에서 테스트 이론적 근거를 추출하기가 어렵다는 것을 알게되었습니다. 누구나 C ++ 사용자들 (위원회 위원, 서적 저자, Google, Facebook, Microsoft 등)이 어떻게 접근하는지에 대한 좋은 예나 게시물이 있다면 도움이 될 것입니다.

최신 정보

이 사이트를 작성한 후이 사이트와 웹을 검색했습니다. 좋은 물건을 찾았습니다.

안타깝게도이 모든 것이 오히려 Java / C # 중심입니다. Java / C #에서 많은 테스트를 작성하는 것은 큰 문제가 아니므로 일반적으로 이점이 비용보다 중요합니다.

그러나 위에서 쓴 것처럼 C ++에서는 더 어렵습니다. 특히 코드 기반이 그렇게 OO가 아닌 경우 좋은 단위 테스트 범위를 얻으려면 문제를 심각하게 엉망으로 만들어야합니다. 예를 들어, 상속받은 응용 프로그램 Graphics은 OpenGL보다 얇은 계층 인 네임 스페이스를 가지고 있습니다. 모든 기능을 직접 사용하는 엔티티를 테스트하려면 인터페이스와 클래스로 바꾸고 모든 엔티티에 주입해야합니다. 한 가지 예일뿐입니다.

따라서이 질문에 답할 때는 시험을 쓰기 위해 다소 큰 투자를해야한다는 것을 명심하십시오.


3
C ++ 단위 테스트의 어려움으로 +1 단위 테스트에서 코드를 변경해야하는 경우 변경하지 마십시오.
DPD

2
@DPD : 확실하지 않습니다. 실제로 테스트 할 가치가 있다면 어떨까요? 현재 코드베이스에서는 모든 그래픽 함수를 직접 호출하기 때문에 시뮬레이션 코드에서 아무것도 테스트 할 수 없으며 모의 / 스텁 할 수 없습니다. 지금 테스트 할 수있는 것은 유틸리티 기능입니다. 그러나 코드를 "테스트 가능"하도록 변경하면 잘못되었다는 데 동의합니다. TDD 지지자들은 종종 이것이 모든 코드를 상상할 수있는 방식으로 향상시킬 것이라고 말하지만 겸손하게 동의하지 않습니다. 모든 것이 인터페이스와 여러 가지 구현을 필요로하는 것은 아닙니다.
futlib

최근의 예를 들어 보겠습니다. 하루 종일 단일 함수 (C ++ / CLI로 작성)를 테스트하려고했는데 테스트 도구 MS Test가이 테스트에서 항상 충돌합니다. 일반 CPP 참조에 문제가있는 것 같습니다. 대신 방금 호출 함수의 출력을 테스트했으며 정상적으로 작동했습니다. 나는 하루 종일 하나의 기능을 낭비했습니다. 그것은 귀중한 시간의 상실이었습니다. 또한 내 요구에 맞는 스터 빙 도구를 얻을 수 없었습니다. 가능하면 수동 스터 빙을했습니다.
DPD

그것은 내가 피하고 싶은 것들입니다 : DI C ++ 개발자는 테스트에 대해 특히 실용적이어야한다고 생각합니다. 테스트를 마쳤으므로 괜찮습니다.
futlib

@ DPD : 이것에 대해 더 많이 생각했고, 당신이 옳다고 생각합니다. 질문은 내가 어떤 종류의 트레이드 오프를 만들고 싶은가입니다. 몇 가지 개체를 테스트하기 위해 전체 그래픽 시스템을 리팩터링 할 가치가 있습니까? 내가 아는 어떤 버그도 없었을 것입니다. 아마도 : 버그가 있음을 느끼기 시작하면 테스트를 작성합니다. 너무 나쁘다 댓글이므로 답변을 드릴 수 없습니다 :)
futlib

답변:


5

단위 테스트는 한 부분 일뿐입니다. 통합 테스트는 팀의 문제를 해결하는 데 도움이됩니다. 모든 종류의 응용 프로그램, 기본 및 OpenGL 응용 프로그램에 대해 통합 테스트를 작성할 수 있습니다. Steve Freemann과 Nat Pryce (예 : http://www.amazon.com/Growing-Object-Oriented-Software-Guided-Signature/dp/0321503627 )의 "테스트에서 제공하는 성장하는 객체 지향 소프트웨어"를 확인해야합니다 . GUI 및 네트워크 통신을 사용하여 응용 프로그램 개발을 단계별로 안내합니다.

테스트되지 않은 테스트 소프트웨어는 또 다른 이야기입니다. Michael Feathers "레거시 코드로 효과적으로 작업"(http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052)을 확인하십시오.


나는 두 권의 책을 모두 알고있다. 1. TDD는 우리와 잘 작동하지 않기 때문에 TDD와 함께 가고 싶지 않습니다. 우리는 시험을 원하지만 종교적으로는 원하지 않습니다. 2. OpenGL 응용 프로그램의 통합 테스트는 어쨌든 가능하지만 너무 많은 노력이 필요합니다. 연구 프로젝트를 시작하지 않고 앱을 계속 개선하고 싶습니다.
futlib

코드가 테스트 가능 (재사용, 유지 관리 가능 등)되도록 설계되지 않았기 때문에 "사실 후"단위 테스트는 항상 "먼저 테스트"보다 어렵습니다. 어쨌든 TDD를 피하더라도 Michael Feathers 트릭 (예 : 이음새)을 고수하십시오. 예를 들어, 함수를 확장하려면 "Sprout method"와 같은 것을 시도하고 새 메소드를 테스트 가능하게 유지하십시오. 가능하지만 더 어려운 IMHO가 가능합니다.
EricSchaefer

비 TDD 코드는 테스트 할 수 있도록 설계되지 않았지만 그 자체로 유지 관리 가능하거나 재사용 할 수 없다고 말하지는 않습니다. 위에서 언급했듯이 인터페이스와 다중 구현이 필요하지 않은 것이 있습니다. Mockito의 문제는 아니지만 C ++에서는 가상 스텁 / 모의하려는 모든 기능을 만들어야합니다. 어쨌든 테스트 할 수없는 코드는 지금 가장 큰 문제입니다. 일부 부분을 테스트 할 수 있도록 매우 근본적인 것들을 변경해야하므로 테스트 대상에 대한 합리적인 이론적 근거가 필요합니다.
futlib

물론 당신은 옳습니다. 필자가 작성한 새로운 코드를 테스트 할 수 있도록주의를 기울일 것입니다. 그러나 지금이 코드 기반에서 작동하는 방식으로는 쉽지 않습니다.
futlib

기능을 추가 할 때는 테스트 방법에 대해 생각하십시오. 못생긴 종속성을 주입 할 수 있습니까? 함수가해야 할 일을 수행한다는 것을 어떻게 알 수 있을까요? 당신은 어떤 행동을 관찰 할 수 있습니까? 정확성을 확인할 수있는 결과가 있습니까? 확인할 수있는 변이체가 있습니까?
EricSchaefer

2

TDD "당신을 위해 잘 작동하지 않았다"부끄러운 일이다. 그것이 그것이 어디로 향해야하는지 이해하는 열쇠라고 생각합니다. TDD가 어떻게 작동하지 않았는지, 더 잘한 일, 왜 어려움이 있었는지 다시 방문하고 이해하십시오.

물론 단위 테스트는 발견 한 버그를 포착하지 못했습니다. 그게 요점입니다. :-) 인터페이스가 작동하는 방식과 제대로 테스트되었는지 확인하는 방법으로 버그를 발견하지 못했기 때문에 해당 버그를 찾지 못했습니다.

결론적으로, 테스트하도록 설계되지 않은 단위 테스트 코드는 어렵습니다. 기존 코드의 경우 단위 테스트 환경보다는 기능 또는 통합 테스트 환경을 사용하는 것이 더 효과적 일 수 있습니다. 특정 영역에 중점을 둔 시스템을 전체적으로 테스트하십시오.

물론 새로운 개발은 TDD의 혜택을받을 것입니다. 새로운 기능이 추가되면 TDD에 대한 리팩토링은 새로운 개발을 테스트하는 데 도움이 될뿐만 아니라 레거시 기능에 대한 새로운 단위 테스트를 개발할 수 있습니다.


4
우리는 약 1 년 반 동안 TDD를했습니다. 그러나 TDD 프로젝트를 TDD없이 테스트했지만 TDD없이 수행 한 이전 프로젝트와 비교하면 실제로 더 안정적이거나 코드를 더 잘 설계했다고 말할 수는 없습니다. 어쩌면 그것은 우리 팀 일 것입니다 : 우리는 많은 것을 짝 짓고 검토합니다. 코드 품질은 항상 꽤 좋았습니다.
futlib

1
TDD가 Flex / Swiz와 같은 특정 프로젝트의 기술에 잘 맞지 않았다고 생각합니다. 개체 간의 상호 작용을 복잡하게 만들고 단위 테스트를 거의 불가능하게 만드는 많은 이벤트와 바인딩 및 주입이 진행됩니다. 이러한 객체를 분리하면 처음부터 올바르게 작동하기 때문에 더 나아지지 않습니다.
futlib

2

C ++에서 TDD를 수행하지 않았으므로 이에 대해 언급 할 수는 없지만 코드의 예상 동작을 테스트해야합니다. 구현이 변경 될 수 있지만 동작은 (보통?) 동일하게 유지되어야합니다. Java C 중심의 세계에서는 공개 메소드 만 테스트하고 예상되는 동작에 대한 테스트를 작성하고 구현 전에 수행합니다 (보통 수행하는 것보다 낫습니다).

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