너무 많은 어설 션 코드 냄새가 있습니까?


19

나는 단위 테스트 및 TDD에 정말 빠져 들었습니다. 테스트에 감염되었습니다.

그러나 단위 테스트는 일반적으로 공용 메소드에 사용됩니다. 때로는 개인적인 방법으로 몇 가지 가정 가정을 테스트해야하지만 그 중 일부는 "위험한"리팩터링으로 더 이상 도움이되지 않기 때문입니다. (테스트 프레임 워크는 개인 메소드를 테스트 할 수 있음을 알고 있습니다).

그래서 개인적인 방법의 첫 번째와 마지막 줄은 모두 주장입니다.

그러나, 나는 "확실히"공개 메소드 (사적뿐만 아니라)에서도 단언을 사용하는 경향이 있음을 알아 차렸다. 공용 메소드 가정이 단위 테스트 프레임 워크에 의해 외부에서 테스트되기 때문에 이것이 "중복 테스트"일 수 있습니까?

누군가가 너무 많은 주장을 코드 냄새로 생각할 수 있습니까?


1
이 어설 션이 릴리스에서 설정 또는 해제되어 있습니까?
jk.

어설 션을 수동으로 활성화 해야하는 Java를 주로 사용합니다.
Florents Tselai 2016 년

그냥이 "버그를 추적하여 생산성 향상을 어설 션"발견 programmers.stackexchange.com/a/16317/32342
Florents Tselai

"너무 많은"을 어떻게 정의합니까?
haylem

@haylem 다른 프로그래머가 코드를 읽고 "이 주장에 질려있다"고 말하면 "너무 많은"주장이 있습니다.
Florents Tselai 2016 년

답변:


26

이러한 어설 션은 가정을 테스트하는 데 실제로 유용하지만 다른 중요한 목적인 문서도 제공합니다. 공용 메소드를 읽는 모든 독자는 테스트 스위트를 보지 않고도 사전 및 사후 조건을 신속하게 판별하기 위해 어설 션을 읽을 수 있습니다. 따라서 테스트 이유가 아니라 문서화 이유 때문에 이러한 주장을 유지하는 것이 좋습니다. 기술적으로는 어설 션을 복제하지만 두 가지 다른 목적으로 사용되며 두 가지 모두에 매우 유용합니다.

어설 션을 유지하는 것이 단순히 주석을 사용하는 것보다 낫습니다. 매번 실행될 때마다 가정을 적극적으로 확인하기 때문입니다.


2
아주 좋은 지적입니다!
Florents Tselai 2016 년

1
주장은 문서이지만, 그것들을 합법적으로 복제하지는 않습니다. 반대로, 동일한 주장이 두 번 이상 필요한 것처럼 보이는 경우 테스트 품질에 대한 의혹도 제기됩니다.
얌 마르코비치

1
@YamMarcovic 두 개의 "중복 된"코드 조각이 서로 다른 두 가지 고유 한 목적을 제공하기 때문에 이것이 허용되는 것 같습니다. 중복에도 불구하고 위치에두면 도움이된다고 생각합니다 . 분석법에 명제를 갖는 것은 문서화에 매우 중요하며 테스트에 분명히 필요합니다.
Oleksi 2016 년

2
나를 위해 코드에서 단언은 단위 테스트 단언을 보완합니다. 테스트 범위는 100 %가 아니며 코드의 어설 션은 실패한 단위 테스트의 범위를 좁히는 데 도움이됩니다.
sebastiangeiger 2016 년

15

계약을 통해 직접 설계 하려고하는 것 같습니다 .

DbC를 수행하는 것이 좋지만 최소한 기본적으로 언어를 지원하는 언어 (예 : Eiffel )로 전환하거나 플랫폼에 대한 계약 프레임 워크 (예 : Microsoft Code Contracts for .NET)를 사용해야합니다 .에펠 탑보다 훨씬 강력하고, 가장 정교한 계약 프레임 워크 일 것입니다. 그렇게하면 계약의 힘을 더 잘 활용할 수 있습니다. 예를 들어 기존 프레임 워크를 사용하면 문서 또는 IDE에 계약을 표시 할 수 있습니다 (예 : .NET 용 Code Contracts는 IntelliSense에 표시되어 있으며 VS Ultimate를 사용하는 경우 컴파일 타임에 자동 정리 증명을 통해 정적으로 검사 할 수도 있음) 마찬가지로 많은 Java 계약 프레임 워크에는 계약을 JavaDoc API 문서로 자동 추출하는 JavaDoc doclet이 있습니다.

그리고 상황에 따라 수동으로 수행 할 수있는 대안이 없다는 것이 밝혀 지더라도 이제는 그것이 무엇인지 알고 있으며 그것에 대해 읽을 수 있습니다.

간단히 말해, 실제로 DbC를 수행하고 있다면 모르는 경우에도 그 주장은 완벽합니다.


4

입력 매개 변수를 완전히 제어 할 수 없을 때마다 간단한 오류를 사전에 테스트하는 것이 좋습니다. 예를 들어 null에 실패합니다.

그들은 코드가 적절하게 실패하는지 테스트해야한다 이것은, 당신의 검사 결과의 중복되지 않습니다 주어진 나쁜 입력 매개 변수를 다음 문서 것을 .

나는 당신이 리턴 매개 변수를 주장해서는 안된다고 생각합니다 (독자가 이해하기 원하는 불변성을 가지고 있지 않는 한). 이것은 또한 단위 테스트의 일입니다.

개인적으로 나는 assert자바 의 문장을 좋아하지 않습니다 . 왜냐하면 그것들은 해제 될 수 있고 잘못된 보안이기 때문입니다.


1
+1 "자바의 assert 문이 마음에 들지 않습니다. 왜냐하면 그것들은 해제 될 수 있고 잘못된 보안이기 때문입니다."
Florents Tselai 2016 년

3

입력을 제어하지 않고 가정이 깨질 가능성이 있기 때문에 공개 메소드에서 어설 션을 사용하는 것이 훨씬 중요하다고 생각합니다.

입력 조건 테스트는 모든 공개 및 보호 된 방법으로 수행해야합니다. 입력이 전용 메소드로 직접 전달되면 입력 테스트가 중복 될 수 있습니다.

내부 조건 (예 : 전용 메소드)에서 출력 조건 (예 : 객체 상태 또는 반환 값! = null)을 테스트해야합니다. 추가 계산이나 내부 상태 변경없이 출력이 전용 메서드에서 공용 메서드의 출력으로 직접 전달되는 경우 공용 메서드의 출력 조건을 테스트하는 것이 중복 될 수 있습니다.

그러나 Oleksi에 동의하면 중복성이 가독성을 높이고 유지 관리 성이 향상 될 수 있다는 점에 동의합니다 (직접 할당 또는 반환이 더 이상 발생하지 않는 경우).


4
공용 인터페이스의 사용자 (호출자)가 오류 조건 또는 유효하지 않은 인수 조건을 유발할 수있는 경우, 적절한 오류 처리를 완전히 수행해야합니다. 이는 최종 사용자에게 의미가있는 오류 메시지의 형식을 지정하고 오류 코드, 로깅 및 데이터 복구 또는 정상 상태로의 복원을 시도합니다. 어설 션으로 올바른 오류 처리를 대체하면 코드의 안정성이 떨어지고 문제를 해결하기가 더 어려워집니다.
rwong

단정에는 로깅 및 예외 발생 (또는 C--의 오류 코드)이 포함될 수 있습니다.
Danny Varod

3

어설 션 및 '적절한'오류 / 예외 처리가 구현되는 방법에 대한 세부 정보가 답변과 관련이 있기 때문에이 문제에 대해 언어에 구애받지 않습니다. Java & C ++에 대한 나의 지식을 바탕으로 내 $ 0.02입니다.

당신이 배에 가지 않고 그것들을 어디에나 두지 않는다고 가정 할 때, 개인적인 방법의 주장은 좋은 것 입니다. 실제로 간단한 방법을 사용하거나 불변 필드와 같은 것을 반복적으로 확인하면 코드가 불필요하게 복잡해집니다.

공개 방법의 주장은 일반적으로 피하는 것이 가장 좋습니다. 메소드 계약이 위반되지 않았는지 확인하는 등의 작업을 계속 수행해야하지만 의미있는 메시지와 함께 적절한 유형의 예외를 발생시키고 가능한 경우 상태를 되 돌리는 등의 작업을 수행해야합니다. 적절한 오류 처리 처리 ").

일반적으로 개발 / 디버깅 을 돕기 위해 어설 션 만 사용해야합니다 . API를 사용하는 사람이 코드를 사용할 때 어설 션이 활성화되어 있다고 가정 할 수 없습니다. 코드를 문서화하는 데 약간의 도움이되지만 동일한 것을 문서화하는 더 좋은 방법이 있습니다 (예 : 메소드 문서화, 예외).


2

(대부분의) 예외적 인 답변 목록, 많은 주장 및 중복의 또 다른 이유는 클래스가 어떻게, 언제 또는 누구에 의해 수업 시간 동안 수정되는지 알지 못하기 때문입니다. 1 년 안에 죽을 코드를 버리면 걱정할 필요가 없습니다. 20 년 이상 사용할 코드를 작성하는 경우에는 다르게 보일 것입니다. 가정 한 내용이 더 이상 유효하지 않을 수 있습니다. 그런 변화를하는 사람은 당신의 주장에 감사 할 것입니다.

또한 모든 프로그래머가 완벽하지는 않습니다. 다시 말하지만이 주장은 이러한 "슬립 업"중 하나가 너무 멀리 전파되지 않음을 의미합니다.

이러한 주장 (및 가정에 대한 다른 점검)이 유지 보수 비용을 줄이는 데 미칠 영향을 과소 평가하지 마십시오.


0

중복 된 어설 션을 갖는 것은 그 자체로는 잘못된 것이 아니지만 어설 션을 "확실히 확인"하는 것이 최선이 아닙니다. 실제로 각 테스트가 정확히 달성하려고하는 것으로 요약됩니다. 절대적으로 필요한 것을 주장하십시오. 테스트에서 Moq를 사용하여 메소드가 호출되었는지 확인하는 경우, 해당 메소드가 호출 된 후 어떤 일이 발생하는지는 중요하지 않으며 테스트는 메소드가 호출되었는지 확인하는 것만 관련됩니다.

모든 단일 단위 테스트에 하나 또는 두 개를 제외하고 동일한 어설 션 세트가있는 경우, 리팩터링 할 때 리 팩터의 실제 영향을 표시하는 대신 동일한 이유로 약간의 테스트가 모두 실패 할 수 있습니다. 모든 테스트를 실행하는 상황에서 결국 모든 테스트가 동일한 어설 션을 가지고 있기 때문에 모두 실패하고, 실패를 수정하고, 테스트를 다시 실행하고, 다른 이유로 실패하며, 실패를 수정합니다. 끝날 때까지 반복하십시오.

테스트 프로젝트의 유지 관리도 고려하십시오. 새 매개 변수를 추가하거나 출력이 약간 씩 조정되면 어떻게됩니까? 다수의 테스트를 거쳐 어설 션을 변경하거나 어설 션을 추가해야합니까? 또한 코드에 따라 모든 어설 션을 전달하기 위해 훨씬 더 설정해야 할 수도 있습니다.

단위 테스트에 중복 된 어설 션을 포함시키려는 매력을 이해할 수 있지만 실제로는 과도합니다. 나는 첫 테스트 프로젝트와 같은 길을 갔다. 유지 보수만으로도 견딜 수 없었기 때문에 나는 그것을 멀리했습니다.


0

그러나 단위 테스트는 공용 메소드에 사용됩니다.

테스트 프레임 워크에서 접근자를 허용하는 경우 단위 테스트 개인 메소드도 좋은 아이디어 (IMO)입니다.

누군가가 너무 많은 주장을 코드 냄새로 생각할 수 있습니까?

나는한다. 주장은 괜찮지 만, 첫 번째 목표는 시나리오가 불가능 해 지도록 만드는 것입니다 . 그것이 일어나지 않는다는 것만이 아닙니다.


-2

나쁜 습관입니다.

공개 / 비공개 메소드를 테스트해서는 안됩니다. 수업을 전체적으로 테스트해야합니다. 커버리지가 좋은지 확인하십시오.

경험적으로 각 방법을 개별적으로 테스트하는 (기본) 방식으로 가면 앞으로 수업을 리팩터링하는 것이 매우 어려울 것입니다. 그리고 이것이 TDD가 할 수있는 최고의 일 중 하나입니다.

게다가, 그것은 이다 중복. 또한 코드 작성자가 자신이하는 일을 실제로 알지 못했음을 제안합니다. 그리고 재미있는 것은 당신이하는 것 입니다.

일부 사람들은 테스트 코드를 프로덕션 코드보다 덜주의해서 취급합니다. 그들은해서는 안됩니다. 내 경험에 따르면 테스트를 더 신중하게 다루는 것이 좋습니다. 그들은 그만한 가치가 있습니다.


-1 클래스 전체를 단위 테스트하는 것은 테스트 당 하나 이상의 것을 테스트하기 때문에 위험 할 수 있습니다. 이것은 실제로 취성 테스트를합니다. 한 번에 하나의 동작을 테스트해야하며 이는 종종 테스트 당 하나의 방법 만 테스트하는 것과 같습니다.
Oleksi 2016 년

또한 "코드 작성자가 자신이하는 일을 실제로 알지 못했음을 제안합니다 ...]. 미래 개발자들은 특정 방법이 무엇인지 명확하지 않을 수 있습니다. 이 경우 어설 션 형태로 사전 및 사후 조건을 갖는 것이 코드 조각을 이해하는 데 매우 중요합니다.
Oleksi 2016 년

2
@Oleksi 좋은 테스트는 모든 관련없는 세부 사항을 주장하는 것이 아니라 유효한 사용 시나리오에 관한 것입니다. 중복 된 주장은 의도가 불분명하기 때문에 실제로 코드 냄새가 나며 방어 프로그래밍의 또 다른 나쁜 예일뿐입니다.
얌 마르코비치
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.