간단한 (자체 포함 된) 기능에 대한 테스트를 유지해야합니까?


36

이걸 고려하세요:

public function polynominal($a, $b, $c, $d)
{
    return  $a * pow($x, 3) + $b * pow($x, 2) + $c * $x + $d;
}

위 함수에 대한 다양한 테스트를 작성하고 자신과 다른 사람들에게 "작동"한다고 증명한다고 가정하십시오.

그렇다면 왜 그런 시험을 치르고 행복하게 살 수 있습니까? 내 요점은 일부 기능이 작동하는 것으로 입증 된 후에 지속적으로 테스트 할 필요가 없다는 것입니다. 나는이 기능을 테스트 할 필요가있는 카운터 포인트를 찾고 있습니다. 왜냐하면 ... ... 그렇습니다. 테스트 할 필요가 없습니다 ...


32
코드를 변경하지 않으면 어제 작동하면 내일도 작동한다는 것이 모든 기능에 해당되는 것은 아닙니까? 요점은 소프트웨어 변경 되었다는 것 입니다.
5gon12eder

3
아무도 override_function('pow', '$a,$b', 'return $a * $b;');자신의 올바른 마음에 글을 쓰지 않을 것입니다 ... 복잡한 숫자를 처리하기 위해 다시 쓰려고 시도하지 마십시오.

8
그래서 ... 음 .. "버그가없는 코드임이 증명되었습니다"... 버그가 있습니다.

이와 같은 작은 기능의 경우 속성 기반 테스트를 고려할 수 있습니다. 속성 기반 테스트는 테스트 케이스를 자동으로 생성하고 미리 결정된 변형을 테스트합니다. 그들은 불변량을 통해 문서를 제공하므로 유지하는 데 유용합니다. 이와 같은 간단한 기능의 경우 완벽합니다.
Martijn

6
또한 그 기능은 호너의 형태 (($a*$x + $b)*$x + $c)*$x + $d를 바꾸는 데 큰 도움 이 될 수 있는데, 이는 잘못되기 쉽지만 종종 훨씬 빠릅니다. 변경되지 않는다고 생각한다고해서 변경되지 않는다는 의미는 아닙니다.
Michael Anderson

답변:


78

회귀 테스트

그것은 회귀 테스트 에 관한 것 입니다.

다음 개발자가 당신의 방법을보고 당신이 마법의 숫자를 사용하고 있음을 알았다고 상상해보십시오. 그는 마법의 숫자가 악하다고 들었습니다. 그래서 그는 두 개의 상수를 생성합니다. 하나는 숫자 2에, 다른 하나는 숫자 3에 대한 것입니다.이 변화를하는 데 아무런 문제가 없습니다. 그가 이미 올바른 구현을 수정 한 것과는 다릅니다.

산만 해져서 두 상수를 뒤집습니다.

그는 코드를 커밋하고 커밋 후에는 회귀 테스트가 없기 때문에 모든 것이 잘 작동하는 것 같습니다.

어느 날 (몇 주 후에) 다른 곳에서 무언가가 깨질 수 있습니다. 그리고 다른 곳에서, 나는 코드베이스의 완전히 반대 위치를 의미 polynominal합니다. 이 기능 은 기능 과 관련이없는 것 같습니다 . 몇 시간의 고통스러운 디버깅 으로 범인이됩니다. 이 기간 동안 응용 프로그램은 계속해서 생산에 실패하여 고객에게 많은 문제를 일으 킵니다.

작성한 원래 테스트를 유지하면 그러한 고통을 예방할 수 있습니다. 산만해진 개발자는 코드를 커밋하고 거의 즉시 그가 무언가를 깨뜨린 것을 보게됩니다. 이러한 코드는 프로덕션에 도달하지도 않습니다. 단위 테스트는 추가로 오류 위치에 대해 매우 정확합니다 . 그것을 해결하는 것은 어렵지 않을 것입니다.

부작용 ...

실제로 대부분의 리팩토링은 회귀 테스트를 기반으로합니다. 약간 변경하십시오. 테스트. 통과하면 모든 것이 정상입니다.

부작용은 테스트가 없다면 실제로 리팩토링으로 인해 코드가 깨질 위험이 크다는 것입니다. 많은 경우를 감안할 때 리팩토링 수행 해야한다고 경영진에게 설명하기가 이미 어렵습니다 .

완전한 테스트 스위트를 사용함으로써 리팩토링 및보다 나은 코드를 권장합니다. 위험이 없으며 정기적으로 리팩토링을 더욱 유혹하고 있습니다.

요구 사항 변경

또 다른 필수 요소는 요구 사항이 변경된다는 것입니다. 복잡한 숫자를 처리 하라는 메시지가 표시 될 수 있으며 갑자기 이전 테스트를 찾아서 복원하고 새 테스트를 추가하기 위해 버전 관리 로그를 검색해야합니다.

왜이 모든 번거 로움이 있습니까? 나중에 추가하기 위해 테스트를 제거해야하는 이유는 무엇입니까? 당신은 처음부터 그들을 유지했을 수 있습니다.


Pedantic note : 위험은 없습니다. ;)
jpmc26

2
회귀는 테스트를위한 가장 중요한 이유입니다. 코드가 책임에 대해 명확하고 전달 된 내용 만 사용하더라도 (예 : 전역 없음) 우연히 무언가를 깨뜨리는 것은 너무 쉽습니다. 테스트는 완벽하지는 않지만 여전히 훌륭합니다 (그리고 거의 항상 같은 버그가 다시 나타나는 것을 막아 주므로 대부분의 고객은 매우 불만족합니다). 테스트가 작동하면 유지 관리 비용이 없습니다. 그들이 작동을 멈 추면 버그를 발견했을 것입니다. 테스트없이 수천 개의 글로벌이있는 레거시 애플리케이션을 작업 중입니다. 테스트를하지 않아도 필요한 변경을 많이하지는 않습니다.
Luaan

또 다른 비고 : 일부 "마법의"숫자는 실제로는 괜찮으며 상수로 바꾸는 것은 나쁜 생각입니다.
중복 제거기

3
@Deduplicator 우리는 알고 있지만, 특히 신입생으로 훈련 된 많은 주니어 프로그래머는 맹목적으로 따르는 맹목에 대해 매우 열심입니다. "매직 넘버는 악하다"는 것도 그 중 하나입니다. 다른 하나는 "한 번 이상 사용 된 것은 메소드로 리팩토링되어야한다"는 것인데, 극단적 인 경우에는 단 하나의 문장 만 포함하는 수많은 메소드로 이어진다 (그런 다음 왜 성능이 갑자기 떨어졌는지, 왜 콜 스택에 대해 배우지 않았는지 궁금하다).
jwenting

@jwenting : MainMa가 "이 변경을 수행하는 데 아무런 문제가 없습니다"라고 썼기 때문에이 메모를 추가했습니다.
중복 제거기

45

버그가 없을 정도로 단순한 것은 없기 때문입니다.

귀하의 코드는 얼굴에 버그가없는 것으로 보입니다. 실제로는 다항식 함수의 간단한 프로그래밍 방식 표현입니다.

버그가있는 것 외에는 ...

public function polynominal($a, $b, $c, $d)
{
    return  $a * pow($x, 3) + $b * pow($x, 2) + $c * $x + $d;
}

$x는 코드에 대한 입력으로 정의되지 않으며 언어 또는 런타임 또는 범위에 따라 함수가 작동하지 않거나 잘못된 결과 가 발생하거나 우주선이 충돌 할 수 있습니다 .


추가:

지금은 코드 버그가 없다고 생각할 수 있지만 그 시간이 얼마나 남아 있는지 말하기는 어렵습니다. 그런 사소한 코드 조각에 대한 테스트를 작성하는 것은 가치가 없다고 주장 할 수 있지만, 이미 테스트를 작성하고 작업을 수행하고 삭제하면 확실한 안전 가드가 삭제됩니다.

테스트 스위트가 제공하는 적용 범위를 잘 나타내는 코드 적용 서비스 (예 : coveralls.io)가 추가로 주목됩니다. 모든 코드 라인을 포함함으로써 수행하는 테스트의 양 (품질이 아닌 경우)을 알맞게 측정 할 수 있습니다. 많은 작은 테스트와 함께 이러한 서비스는 최소한 버그가 발생했을 때 찾을 수 없는 곳을 알려줍니다 .

궁극적으로 이미 작성된 테스트가있는 경우 유지하십시오 . 삭제로 인해 공간이나 시간이 절약되므로 나중에 버그가 발생할 경우 기술 부채보다 훨씬 적습니다.


대안은 비 동적 언어가 아닌 언어로 전환하는 것입니다. 단위 테스트는 일반적으로 컴파일 시간 확인이 불충분 한 경우에 대한 해결 방법이며 일부 언어는이 en.wikipedia.org/wiki/Agda_(programming_language)
Den

21

예. 100 % 확신을 가지고 확실하게 말할 수 있다면 :이 함수는 절대로 편집되지 않으며 실패 할 수있는 상황에서는 절대 실행되지 않습니다. 말할 수 있으면 테스트를 중단하고 모든 시간에 수 밀리 초를 절약 할 수 있습니다 CI 빌드.

그러나 우리는 할 수 없습니다. 또는 많은 기능을 사용할 수 없습니다. 그리고 어떤 신뢰 임계 값을 정확하게 만족시키는 지, 주어진 함수의 불변성과 불완전성에 대해 얼마나 많은 신뢰를 갖는지를 결정하는 것보다 항상 모든 테스트를 실행하는 규칙을 갖는 것이 더 간단합니다.

그리고 처리 시간이 저렴합니다. 절약 된 밀리 초는 여러 번 곱해도 모든 기능을 수행하는 데 시간이 걸리는 것을 정당화하기에 거의 충분하지 않습니다. 다시 테스트 할 필요가 없다는 확신이 있습니까?


나는 이것이 당신이 여기에서 제기하는 아주 좋은 지적이라고 생각합니다. 난 이미 두 사람 지출 볼 수있는 시간을 몇 가지 작은 기능을 테스트 유지에 대한 주장.
Kapol

@ 카폴 (Kapol) : 논쟁이 아니며, 갈 수있는 것과 남을 수있는 것을 결정하기위한 회의, 어떤 기준을 결정하기 위해 사용해야 하는가, 기준을 문서화 할 곳, 최종 결정에 서명하는 사람 ...
jmoreno

12

다른 답변에서 언급 된 모든 것이 정확하지만 하나 더 추가 할 것입니다.

문서

잘 작성된 단위 테스트는 개발자에게 함수의 기능, 입력 / 출력 기대치 및 더 중요한 것으로 예상되는 동작을 설명 할 수 있습니다.

버그를 쉽게 발견하고 혼동을 줄일 수 있습니다.

다항식, 기하학 또는 대수학을 모두 기억하는 것은 아닙니다. :) 버전 제어에 체크인 한 좋은 단위 테스트는 저를 기억합니다.

이 재스민 소개에서 문서보기로 얼마나 유용한의 예를 들면 다음과 같습니다 http://jasmine.github.io/edge/introduction.html 그것을 부하에 몇 초를주고, 그 다음 아래로 스크롤합니다. Jasmine API 전체가 단위 테스트 출력으로 문서화되어 있습니다.

[@Warbo의 피드백을 기반으로 업데이트] 테스트는 최신 상태를 유지하며 테스트에 실패하면 실패하므로 일반적으로 CI를 사용하는 경우 빌드가 실패합니다. 외부 문서는 코드와 독립적으로 변경되므로 반드시 최신 정보는 아닙니다.


1
암시 적으로 남겨둔 문서의 일부로 테스트를 사용하면 큰 이점이 있습니다. 자동으로 검사됩니다. 다른 형태의 문서, 예. 웹 페이지의 설명 주석이나 코드 스 니펫은 코드가 발전함에 따라 최신 버전이 아닐 수 있습니다. 더 이상 정확하지 않으면 단위 테스트에서 오류가 발생합니다. 그 재스민 페이지는 이것의 극단적 인 예입니다.
Warbo

난 당신이 단위 테스트에 모두 컴파일을 동일한 코드 조각을 가질 수 있고, HTML 문서에 삽입받을 수 있도록, 그들의 단위 테스트와 D 및 녹 같은 일부 언어는 자신의 문서 생성을 통합하는 것을 추가 할
Idan Arye

2

현실 점검

예산 및 일정 중에 테스트가 "시간 낭비"인 다음, 고객이 버그를 처리하면 "품질 보증의 기본 부분"인 까다로운 환경에 처해있어 다른 사람들보다 유동적입니다.

예산이 있습니다. 당신의 임무는 당신이 긁을 수있는 "최고의"정의가 무엇이든 그 예산에서 최고의 제품을 얻는 것입니다 (정의하기 쉬운 단어는 아닙니다). 이야기의 끝.

테스트는 인벤토리 도구입니다. 수백만 달러 또는 수십억 달러를 절약 한 오랜 역사를 가진 좋은 도구이기 때문에 사용해야합니다 . 기회가 주어지면 이러한 간단한 기능에 테스트를 추가해야합니다. 언젠가는 피부를 구할 수 있습니다.

그러나 실제 상황에서는 예산 및 일정 제약 조건이 발생하지 않을 수 있습니다. 자신을 절차의 노예로 삼지 마십시오. 테스트 기능은 훌륭하지만 언젠가는 코드가 아닌 단어로 개발자 문서를 작성하는 데 더 많은 시간을 할애 할 수 있으므로 다음 개발자에게는 테스트가 많이 필요하지 않습니다. 또는 코드베이스를 리팩토링하는 것이 더 좋을 수 있으므로 짐승처럼 힘들지 않아도됩니다. 또는 예산과 일정에 대해 상사와 이야기하는 것이 더 좋을 것이므로 다음 번 자금 조달이 진행될 때 입찰 대상이 무엇인지 더 잘 이해할 수 있습니다.

소프트웨어 개발은 ​​균형입니다. 시간을 보내는 데 더 좋은 방법이 없도록하기 위해 항상하고있는 일의 기회 비용을 세십시오.


4
이 경우 이미 테스트가 있었으므로 테스트 작성 여부가 아니라 각 빌드 또는 릴리스 또는 모든 테스트를 실행하기 위해 스케줄을 지정하여 커밋하고 실행할지 여부가 문제입니다.
Paŭlo Ebermann

0

예, 테스트를 계속 유지하고 테스트를 계속 실행하십시오.

단위 테스트는 귀하 (및 다른 사람)를 자신 (및 자신)으로부터 보호하기위한 것입니다.

테스트를 좋은 아이디어로 유지하는 이유는 무엇입니까?

  • 새로운 요구 사항 및 추가 기능에 직면하여 이전 요구 사항의 기능을 검증합니다.
  • 리팩토링 연습이 올바른지 확인
  • 내부 문서-코드 사용 방법
  • 회귀 테스트, 상황 변경
    • 변경 사항으로 인해 이전 코드가 손상됩니까?
    • 변경에 추가 변경 요청이나 현재 기능 또는 코드에 대한 업데이트가 필요합니까?
  • 테스트가 이미 작성되었으므로 유지하십시오. 유지 보수 비용을 줄이면 이미 시간과 돈이 소비됩니다.

2
이것은 제공된 다른 답변보다 실질적인 것을 제공하지 않는 것 같습니다.

1
이전에 게시하는 데 문제가 있었지만 회상하면 좋은 요약입니다. 제거하겠습니다.
Niall

-1

개발자 문서

  • (다른 개발자로서) 이것이 테스트되었음을 ​​어떻게 알 수 있습니까?
  • 자체 포함 함수 에서 버그를 수정 하려면 이미 고려한 버그가 없는지 어떻게 알 수 있습니까?
  • 복잡성 지표 : 테스트 횟수는 무언가가 얼마나 복잡한지를 나타내는 좋은 척도입니다. 이것은 성숙하고 안정적이거나 부풀어 오르고 연결되어 있기 때문에 만지지 않아야 함을 나타낼 수 있습니다.

사용자 설명서

  • 보류중인 빈약 한 문서, {0, 음수 값, 빈 세트 등}이 허용되는지와 예상되는 반환 값이 무엇인지 확인할 수 있습니다.
  • 또한 객체 / 함수를 사용하는 방법에 대한 좋은 예를 제공합니다.

1
이것은 이전 답변에서 만들어지고 설명 된 점에 비해 실질적인 것을 제공하지 않는 것 같습니다. "좋은 요약"조차 이미 게시되었습니다 (내 취향에 따라 좋지는 않지만 아 잘)
gnat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.