계약 기반 프로그래밍 및 단위 테스트


13

나는 다소 방어적인 프로그래머이자 Microsoft의 Code Contracts의 열렬한 팬입니다.

이제는 항상 C #을 사용할 수 없으며 대부분의 언어에서 내가 가진 유일한 도구는 어설 션입니다. 그래서 나는 보통 다음과 같은 코드로 끝납니다.

class
{       
    function()
    {   
         checkInvariants();
         assert(/* requirement */);

         try
         {
             /* implementation */
         }
         catch(...)
         {
              assert(/* exceptional ensures */);                  
         }
         finally
         {
              assert(/* ensures */);
              checkInvariants();
         }
    }

    void checkInvariants()
    {
         assert(/* invariant */);
    }
}

그러나이 패러다임 (또는 호출 할 것이 무엇이든)은 많은 코드 혼란을 초래합니다.

실제로 노력할만한 가치가 있는지 그리고 적절한 단위 테스트가 이미 이것을 포함하는지 궁금해하기 시작했습니다.


6
단위 테스트를 통해 어설 션을 응용 프로그램 코드 밖으로 이동시킬 수 있으므로 혼란을 피할 수 있지만 실제 프로덕션 시스템에서 발생할 수있는 모든 사항을 확인할 수는 없습니다. 따라서 IMO 코드 계약에는 특히 정확성이 중요한 중요한 코드의 경우 몇 가지 장점이 있습니다.
Giorgio

기본적으로 개발 시간, 유지 관리 성, 가독성 대 코드 범위가 향상 되었습니까?
ronag

1
매개 변수의 정확성을 확인하기 위해 코드에서 어설 션을 주로 사용하고 (예 : null 인 경우) 단위 테스트에서 추가로 해당 어설 션을 확인합니다.
artjom

답변:


14

나는 당신이 그것을 "vs"로 생각해야한다고 생각하지 않습니다.
@Giorgio의 의견에서 언급했듯이 코드 계약은 변형을 확인하고 (생산 환경에서) 단위 테스트는 이러한 조건이 충족 될 때 예상대로 코드가 작동하는지 확인하는 것입니다.


2
조건이 충족 되지 않으면 코드가 작동하는지 (예 : 예외가 발생하는지) 테스트하는 것이 중요하다고 생각합니다 .
svick December

6

계약은 단위 테스트가하지 않는 것 중 적어도 하나를 도와줍니다. 공개 API를 개발할 때 사람들이 코드를 사용하는 방법을 단위 테스트 할 수 없습니다. 그러나 여전히 메소드에 대한 계약을 정의 할 수 있습니다.

나는 개인적으로 모듈의 공개 API를 다룰 때만 계약에 대해 엄격하게 할 것입니다. 다른 많은 경우에는 노력의 가치가 없을 것입니다 (대신 단위 테스트를 대신 사용할 수 있음). 그러나 이것은 내 의견 일뿐입니다.

그렇다고 계약에 대해 생각하지 않는 것이 좋습니다. 나는 항상 그들에 대해 생각합니다. 항상 명시 적으로 코드를 작성해야한다고 생각하지 않습니다.


1

이미 언급했듯이 계약 및 단위 테스트는 다른 목적을 가지고 있습니다.

계약은 전제 조건이 충족되고 코드가 올바른 매개 변수로 호출되는지 확인하기위한 방어 프로그래밍에 관한 것입니다.

다른 시나리오에서 코드가 작동하는지 확인하기위한 단위 테스트. 이것들은 '이빨이있는 스펙'과 같습니다.

주장은 코드를 강력하게 만드는 것이 좋습니다. 그러나 코드가 많이 추가 될까 걱정되면 디버깅 중에 일부 위치에 조건부 중단 점을 추가하고 어설 션 수를 줄이는 것이 좋습니다.


0

checkVariants () 호출에있는 모든 것은 테스트를 통해 수행 할 수 있습니다. 실제로 많은 노력 (외부 종속성, 커플 링 레벨 등)에 따라 얼마나 많은 노력이 필요하지만 한 관점에서 코드를 정리합니다. 어설 션에 대해 개발 된 코드베이스가 얼마나 리팩터링이 없는지 테스트 할 수 있습니다.

@duros에 동의합니다. 독점적이거나 경쟁적인 접근 방식으로 생각해서는 안됩니다. 실제로 TDD 환경에서는 '요구 사항'주장이 테스트가 필요하다고 주장 할 수도 있습니다.)

어설 션은 실제로 실패한 검사를 수정하기 위해 무언가를 수행하지 않는 한 코드를 더 강력하게 만들지 않으며 일반적으로 문제의 첫 징후에서 처리를 중단하여 데이터가 손상되거나 유사한 것을 중지합니다.

테스트 중심 / 잘 테스트 된 솔루션은 일반적으로 상호 작용하는 구성 요소를 개발하면서 문제의 원인에 더 가깝게 처리하는 동안 잘못된 입력 및 출력의 많은 원인 / 이유에 대해 이미 생각 및 / 또는 발견했을 것입니다.

소스가 외부에 있고 소스를 제어 할 수 없다면 다른 코드 문제를 처리하는 코드를 어지럽히 지 않으려면 소스와 구성 요소 사이에 일종의 데이터 정리 / 어설 션 구성 요소를 구현하고 확인을하십시오. .

또한 누군가가 개발 한 xUnit 또는 다른 테스트 라이브러리가없는 사용중인 언어가 궁금합니다. 요즘에는 모든 것에 대해 꽤 많은 것이 있다고 생각합니까?


0

단위 테스트 및 코드 계약 외에도 다른 측면을 강조하겠다고 생각했는데, 이는 인터페이스를 정의 할 때 가치가있어 코드를 잘못 호출 할 가능성을 없애거나 줄입니다.

항상 쉽지는 않지만 "이 코드를 더 완벽하게 만들 수 있을까요?"라는 질문을 할 가치가 있습니다.

C #의 작성자 인 Anders Hejlsberg는 C #에서 가장 큰 실수 중 하나는 nullable이 아닌 참조 유형을 포함하지 않았다고 말했습니다. 필요한 가드 코드 혼란이 존재하는 주된 이유 중 하나입니다.

여전히 필요하고 충분한 양의 가드 코드를 갖도록 리팩토링하면 내 경험에서 더 유용하고 유지 보수가 쉬운 코드가 만들어집니다.

나머지 부분에서 @duros에 동의하십시오.


0

두 가지를 모두 수행하되 의도를 명확히하기 위해 정적 도우미 메서드를 만드십시오. 이것이 Google이 Java를 위해 한 일입니다. code.google.com/p/guava-libraries/wiki/PreconditionsExplained를 확인하십시오.

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