자신의 코드를 더 잘 테스트하는 방법 경로를 따라

저는 비교적 새로운 소프트웨어 개발자이며 개선해야 할 것 중 하나는 내 코드를 테스트 할 수있는 능력입니다. 새로운 기능을 개발할 때마다 가능한 모든 경로를 따라 가기가 어려워서 버그를 찾을 수 있습니다. 나는 모든 것이 작동하는 길을 따르는 경향이 있습니다. 나는 이것이 프로그래머에게 잘 알려진 문제라는 것을 알고 있지만, 현재 고용주에 테스터가 없으며 동료들은 이것에 꽤 능숙한 것 같습니다.

우리 조직에서는 테스트 중심 개발이나 단위 테스트를 수행하지 않습니다. 그것은 나에게 많은 도움이 될 것이지만 이것이 바뀌지 않을 것입니다.

이것을 극복하기 위해 내가 무엇을 할 수 있다고 생각합니까? 자신의 코드를 테스트 할 때 어떤 접근법을 사용합니까?



답변

코더의 임무는 물건을 만드는 것입니다.

테스터의 임무는 문제를 해결하는 것입니다.

가장 어려운 것은 방금 만든 것들을 깨는 것입니다. 이 심리적 장벽을 넘어 서면 성공할 수 있습니다.


답변

Franciso, 나는 당신이 말한 것을 바탕으로 몇 가지 가정을 할 것입니다.

“우리는 TDD 나 단위 테스트를 수행하지 않습니다. 그것은 많은 도움이 될 것이지만 이것이 바뀔 것 같지는 않습니다.”

이로 인해 귀하의 팀은 테스트에 많은 가치를 두지 않거나 경영진이 기존 코드를 정리하고 기술적 부채 를 최소화하기 위해 시간을 낭비하지 않을 것 입니다.

먼저, 팀 / 관리자에게 테스트의 가치를 확신시켜야합니다. 외교하십시오. 경영진이 팀을 계속 발전시키고 있다면 모든 릴리스의 결함률과 같은 몇 가지 사실을 보여 주어야합니다. 응용 프로그램 개선 및 향후 요구 사항에 대한 적응력 향상과 같은 다른 문제에 대해서는 결함을 수정하는 데 소요되는 시간이 더 좋을 수 있습니다.

일반적으로 팀과 경영진이 코드를 수정하는 것에 대해 냉담하고 코드가 마음에 들지 않으면 내가 말한대로 설득 할 수 없다면 다른 직장을 찾아야 할 수도 있습니다. 내가 일한 모든 곳 에서이 문제가 다른 정도로 발생했습니다. 적절한 도메인 모델이없는 것부터 팀의 의사 소통이 부족한 것까지 가능합니다.

코드와 개발 한 제품의 품질에 대한 관심은 좋은 속성이며 항상 다른 사람들에게 격려하고 싶은 특성입니다.


답변

C, Objective-C 또는 C ++로 코딩 하는 경우 CLang 정적 분석기 를 사용 하여 소스를 실제로 실행하지 않고 비평 할 수 있습니다.

사용 가능한 메모리 디버깅 도구는 ValGrind, Mac OS X의 Guard Malloc, * NIX의 Electric Fence입니다.

일부 개발 환경은 디버깅 메모리 할당자를 사용할 수있는 옵션을 제공합니다.이 할당기에는 새로 할당 된 페이지 및 새로 해제 된 페이지를 가비지로 채우고 할당되지 않은 포인터의 해제를 감지하고 디버거를 사용하여 각 힙 블록 전후에 일부 데이터를 쓰는 등의 작업이 수행됩니다. 해당 데이터의 알려진 패턴이 변경되면 호출됩니다.

Slashdot의 일부 직원은 디버거에서 새로운 스테핑 소스를 사용하여 단일 스테핑에서 많은 가치를 얻었습니다. “그게 다야”그는 말했다. 나는 항상 그의 조언을 따르지는 않지만 제가 가지고있을 때 매우 도움이되었습니다. 드문 코드 경로를 자극하는 테스트 사례가없는 경우에도 디버거의 변수를 돌려서 이러한 경로를 가져 와서 메모리를 할당 한 다음 디버거를 사용하여 새 포인터를 NULL 대신 NULL로 설정하면됩니다. 메모리 주소를 할당 한 다음 할당 실패 처리기를 단계별로 실행합니다.

어설 션-C, C ++ 및 Objective-C의 assert () 매크로를 사용하십시오. 언어가 어설 션 기능을 제공하지 않으면 직접 작성하십시오.

어설 션을 자유롭게 사용하고 코드에 그대로 둡니다. assert () “테스트를 계속하는 테스트”를 호출합니다. 나는 대부분의 함수의 진입 점에서 전제 조건을 확인하기 위해 가장 일반적으로 사용합니다. 이것은 에펠 프로그래밍 언어에 내장 된 “계약에 의한 프로그래밍”의 한 부분입니다. 다른 부분은 사후 조건, 즉 함수 반환 지점에서 assert ()를 사용하지만 전제 조건만큼 많은 마일리지를 얻지 못한다는 것을 알았습니다.

assert를 사용하여 클래스 불변량을 확인할 수도 있습니다. 클래스가 변하지 않는 클래스를 반드시 요구하지는 않지만, 현명하게 디자인 된 클래스에는 클래스가 있습니다. 클래스 불변은 객체를 일시적으로 일관성이없는 상태로 만들 수있는 멤버 함수 내부가 아닌 항상 참인 조건입니다. 이러한 기능은 반환하기 전에 항상 일관성을 복원해야합니다.

따라서 모든 멤버 함수는 시작 및 종료시 불변을 확인할 수 있으며 클래스는 다른 코드가 언제든지 호출 할 수있는 CheckInvariant라는 함수를 정의 할 수 있습니다.

코드 커버리지 도구를 사용하여 실제로 테스트중인 소스 라인을 확인한 다음 테스트되지 않은 라인을 자극하는 테스트를 설계하십시오. 예를 들어 물리적 메모리가 거의없고 스왑 파일이 없거나 매우 작은 VM 내에서 앱을 실행하여 메모리 부족 처리기를 확인할 수 있습니다.

BOS 파일 시스템을 작성한 Dominic Giampaolo는 스왑없이 BeOS를 실행하지 말라고 강력히 권유했습니다. 이것이 왜 중요한지 확인하지만 일종의 구현 아티팩트 일 것입니다.)

또한 I / O 오류에 대한 코드 응답을 테스트해야합니다. 모든 파일을 네트워크 공유에 저장 한 다음 앱의 작업량이 많은 동안 네트워크 케이블을 분리하십시오. 네트워크를 통해 통신하는 경우 마찬가지로 케이블을 분리하거나 무선을 끄십시오.

특히 분노한 것은 강력한 자바 스크립트 코드가없는 웹 사이트입니다. Facebook의 페이지는 수십 개의 작은 Javascript 파일을로드하지만 그 중 하나가 다운로드되지 않으면 전체 페이지가 중단됩니다. 다운로드를 다시 시도하여 오류 허용을 제공하거나 일부 스크립트가 다운로드되지 않은 경우 합리적인 폴백을 제공 할 수있는 방법이 있어야합니다.

크고 중요한 파일을 작성하는 도중에 디버거 또는 * NIX의 “kill -9″로 앱을 종료하십시오. 앱의 아키텍처가 잘 설정되어 있으면 전체 파일이 쓰여지거나 전혀 쓰여지지 않거나 부분적으로 만 쓰여지면 쓰여진 내용이 손상되지 않고 저장된 데이터를 완전히 사용할 수 있습니다. 파일을 다시 읽을 때 응용 프로그램.

데이터베이스에는 항상 내결함성 디스크 I / O가 있지만 다른 종류의 앱은 거의 없습니다. 저널 파일 시스템은 정전 또는 충돌시 파일 시스템 손상을 방지하지만 최종 사용자 데이터의 손상 또는 손실을 방지하기 위해 아무 것도하지 않습니다. 이는 사용자 응용 프로그램의 책임이지만 데이터베이스 이외의 다른 방법으로는 내결함성을 구현하지 않습니다.


답변

코드 테스트를 볼 때 일반적으로 일련의 사고 과정을 거칩니다.

  1. 이 “사물”을 테스트 가능한 크기의 덩어리로 나누려면 어떻게해야합니까? 테스트하고 싶은 것을 어떻게 분리 할 수 ​​있습니까? 어떤 스텁 / 모의를 만들어야합니까?
  2. 각 청크에 대해 :이 청크를 테스트하여 합리적인 입력 세트에 올바르게 응답하는지 확인하려면 어떻게해야합니까?
  3. 각 청크에 대해 : 청크가 잘못된 입력 (NULL 포인터, 유효하지 않은 값)에 올바르게 응답하는지 어떻게 테스트합니까?
  4. 경계를 어떻게 테스트합니까 (예 : 값이 부호있는 것에서 부호없는 것, 8 비트에서 16 비트로 바뀌는가 등)?
  5. 테스트가 코드를 얼마나 잘 다루고 있습니까? 내가 놓친 조건이 있습니까? [이것은 코드 커버리지 도구를위한 훌륭한 장소입니다.] 누락 된 코드가 있고 실행할 수없는 코드가 있다면 실제로 있어야합니까? [다른 질문입니다!]

내가 찾은 가장 쉬운 방법은 코드와 함께 테스트를 개발하는 것입니다. 코드 조각을 작성하자마자 테스트를 작성하고 싶습니다. 사소한 순환 코드 복잡도로 수천 줄의 코드를 코딩 한 후 모든 테스트를 수행하는 것은 악몽입니다. 몇 줄의 코드를 추가 한 후 하나 또는 두 개의 테스트를 추가하면 정말 쉽습니다.

BTW는 귀하가 근무하는 회사 및 / 또는 동료가 단위 테스트 또는 TDD를 수행하지 않는다고해서 특별히 금지되지 않는 한 시도 할 수 없다는 것을 의미하지는 않습니다. 아마도 그것들을 사용하여 강력한 코드를 만드는 것이 다른 사람들에게 좋은 예가 될 것입니다.


답변

다른 답변에 제공된 조언 외에도 정적 분석 도구 (Wikipedia에는 다양한 언어에 대한 여러 정적 분석 도구 목록 이 있음)를 사용하여 테스트를 시작하기 전에 잠재적 결함을 찾고 관련 메트릭스를 모니터링하는 것이 좋습니다 사이클로 매틱 복잡성 , Halstead 복잡성 측정 , 응집력 및 커플 링과 같은 코드의 테스트 가능성 (팬인 및 팬 아웃으로 측정 가능).

테스트하기 어려운 코드를 찾고 테스트하기 쉽도록하면 테스트 사례를보다 쉽게 ​​작성할 수 있습니다. 또한 결함을 조기에 발견하면 전체 품질 보증 관행 (테스트 포함)에 가치가 추가됩니다. 여기에서 단위 테스트 도구 및 조롱 도구에 익숙해지면 테스트를보다 쉽게 ​​구현할 수 있습니다.


답변

코드에서 가능한 모든 경로를 정의하는 데 도움이 되는 Truth Tables 의 가능한 사용법을 살펴볼 수 있습니다. 복잡한 기능의 모든 가능성을 설명하는 것은 불가능하지만 알려진 모든 경로에 대해 처리가 설정되면 else 사례에 대한 처리를 설정할 수 있습니다.

이 특별한 능력의 대부분은 경험에 의해 배웁니다. 일정 기간 동안 특정 프레임 워크를 사용한 후에는 코드 조각을보고 작은 변경으로 인해 중대한 오류가 발생할 수있는 동작의 패턴과 특징을 볼 수 있습니다. 이것에 대한 당신의 적성을 높이는 유일한 방법은 연습입니다.


답변

당신이 말했듯이 단위 테스트가 필요하지 않다면 직접 코드를 수동으로 끊는 것보다 더 좋은 방법은 없습니다.

코드를 한계 까지 밀어 넣으십시오 . 예를 들어, 경계 한계를 초과하는 함수에 변수를 전달하십시오. 사용자 입력을 필터링하는 기능이 있습니까? 다른 문자 조합을 입력하십시오.

사용자의 관점을 고려하십시오 . 응용 프로그램 또는 기능 라이브러리를 사용할 사용자 중 하나가 되십시오.