동적 언어로 모형을 만드는 동안 유형 오류가 어떻게 감지됩니까?


10

TDD를 수행하는 동안 문제가 발생합니다. 몇 번의 테스트 통과 후 일부 클래스 / 모듈의 반환 유형이 변경됩니다. 정적으로 유형이 지정된 프로그래밍 언어에서, 이전의 조롱 된 객체가 다른 클래스 의 테스트에서 사용되었고 유형 변경을 반영하도록 수정되지 않은 경우 컴파일 오류가 발생합니다.

그러나 동적 언어의 경우 리턴 유형의 변경이 감지되지 않고 다른 클래스 의 테스트 는 여전히 통과합니다. 나중에 실패해야하는 통합 테스트가있을 수 있지만 단위 테스트는 잘못 통과합니다. 이것을 피하는 방법이 있습니까?

간단한 샘플로 업데이트 (일부 언어로 작성된 언어) ...

버전 1 :

Calc = {
    doMultiply(x, y) {return x * y}
}
//.... more code ....

// On some faraway remote code on a different file
Rect = {
    computeArea(l, w) {return Calc.doMultipy(x*y)}
}

// test for Rect
testComputeArea() { 
    Calc = new Mock()
    Calc.expect(doMultiply, 2, 30) // where 2 is the arity
    assertEqual(30, computeArea)
}

이제 버전 2에서

// I change the return types. I also update the tests for Calc
Calc = {
    doMultiply(x, y) {return {result: (x * y), success:true}}
}

... 그런 다음 런타임시 예외가 발생하지만 테스트는 계속 성공합니다.


1
지금까지 해답이 놓친 것처럼 보이는 것은 변경이 포함 된 테스트에 관한 것이 class X아니라 테스트가 프로덕션에서 실행되는 것과 다른 계약에 class Y따라 테스트를 받는 X것입니다.
Bart van Ingen Schenau

Dependency Injection과 관련하여 방금 SO에 대해이 질문을했습니다 . 참조 이유 1 : 종속 클래스 (테스트) 생각 런타임에 변경 될 수 있습니다 . 우리 둘 다 같은 사고 방식을 가지고 있지만 설명이 부족합니다.
Scott Coates

귀하의 질문을 다시 읽고 있지만 해석에 약간 혼란스러워하고 있습니다. 예를 들어 줄 수 있습니까?
Scott Coates

답변:


2

어느 정도까지는 동적 언어로 비즈니스를 수행하는 비용의 일부일뿐입니다. 그렇지 않으면 "충분히 로프를 걸 수있는"것으로 알려진 유연성이 많이 있습니다. 조심해

나에게 문제는 정적 형식의 언어와 다른 리팩토링 기술을 사용하는 것이 좋습니다. 정적 언어에서는 리턴 유형을 부분적으로 대체하여 "컴파일러에 의존"하여 어떤 위치가 중단 될 수 있는지 찾을 수 있습니다. 리턴 타입을 수정하는 것보다 안전하고 아마 더 안전 할 것입니다.

동적 언어에서는 그렇게 할 수 없으므로 반환 유형을 바꾸지 않고 수정하는 것이 훨씬 안전합니다. 아마도 필요한 클래스에 대해 새 클래스를 멤버로 추가하여이를 수정할 수 있습니다.


2

코드가 변경되고 테스트가 여전히 통과되면 테스트에 문제가 있거나 (예 : 어설 션이 누락되었거나) 코드가 실제로 변경 되지 않은 입니다.

그게 무슨 소리 야? 테스트는 코드 부분 간의 계약을 설명합니다. 계약이 "반환 값은 반복 가능해야합니다"인 경우 반환 값을 배열에서 목록 으로 변경하는 것이 실제로 계약의 변경이 아니기 때문에 테스트 실패를 유발하지는 않습니다.

누락 된 어설 션을 피하기 위해 코드 적용 범위 분석 (코드의 어떤 부분을 테스트하지는 않지만 확실하게 테스트 되지 않은 부분 알려줍니다 ), 순환 복잡성 및 NPath 복잡성과 같은 도구를 사용할 수 있습니다. 등 돌리는 것과 코드에서 분사 돌연변이와 돌연변이 테스터 ((이 당신에게 낮은 주장의 수에 결합 된 전체 C1과 C2의 코드 커버리지 달성하는 데 필요한 줄) 에 긍정적으로 음수가,에 객체 등을하고 있는지 여부를 확인 테스트 실패).truefalsenull


+1 테스트 나 코드에 문제가 실제로 바뀌지 않았습니다. 수년간의 C ++ / Java 후에 익숙해지는 데 시간이 걸렸습니다. 동적 언어 코드에서 파트 간 계약은 리턴되는 것이 아니라 리턴되는 것이 포함하고 수행 할 수있는 작업이되어야합니다.
MrFox

@suslik : 사실 이것은 정적 언어와 동적 언어가 아니라 추상 데이터 형식과 객체 지향 데이터 추상화를 사용한 데이터 추상화에 관한 것입니다. 한 객체가 다른 객체를 구별 할 수없는 한 (완전히 다른 유형과 완전히 다른 클래스의 인스턴스 인 경우에도) 다른 객체를 시뮬레이션 할 수있는 능력 은 OO의 전체 아이디어의 기본 입니다. 또는 다른 방식으로 말하면 두 객체가 동일하게 작동하면 클래스의 내용에 관계없이 동일한 유형입니다. 다시 말하면 클래스는 유형이 아닙니다. 불행히도 Java와 C #은 이것을 잘못합니다.
Jörg W Mittag

조롱 된 유닛이 100 % 커버되고 어설 션이 없다고 가정하면 : "foo에 대해 null을 반환해야 함"에서 "foo에 대해 빈 문자열을 반환해야 함"과 같은 더 미묘한 변경은 어떻습니까? 누군가 해당 장치와 테스트를 변경하면 일부 소비 장치가 파손될 수 있으며 모의로 인해 투명합니다. (그리고 아니오 : "계약"에 따라, 모의 모듈을 쓰거나 사용할 때 빈 문자열을 반환 값으로 처리 할 필요가 없습니다. 빈 문자열을 반환하거나 null 만 반환해야하기 때문입니다.) (인터랙션에서 두 모듈의 적절한 통합 테스트만으로도이를 파악할 수 있습니다.)
try-catch-finally
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.