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


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.