모의가 개방 / 폐쇄 원칙을 위반합니까?


13

얼마 전에 나는 찾을 수없는 스택 오버플로 답변에서 공개 API를 테스트해야한다고 설명하는 문장을 읽었으며 저자는 인터페이스를 테스트해야한다고 말했습니다. 저자는 또한 메소드 구현이 변경되면 테스트 케이스를 수정할 필요가 없다고 설명했다. 이렇게하면 테스트중인 시스템이 작동하는 계약을 깨뜨릴 수 있기 때문이다. 즉, 메소드가 작동하지 않으면 테스트가 실패하지만 구현이 변경 되었기 때문에 실패해야합니다.

우리가 조롱에 관해 이야기 할 때 이것은주의를 끌었습니다. 모의는 테스트 대상 시스템의 종속성 호출에 크게 의존하므로 모의는 인터페이스가 아닌 구현과 밀접하게 연결됩니다.

mock vs stub을 연구하는 동안 여러 기사에서 스터브는 mock 대신 mock을 사용해야한다는 데 동의합니다.

내 질문은 :

  1. 모의가 공개 / 폐쇄 원칙을 위반합니까?
  2. 마지막 문단에서 스텁을지지하는 주장에 빠진 것이 있습니까?
  3. 그렇다면 언제 모의하기에 좋은 유스 케이스이고 스텁을 사용하기에 좋은 유스 케이스는 언제입니까?


8
Since mocking relays heavily on expectation calls from system under test's dependencies...나는 이것이 당신이 엉망인 곳이라고 생각합니다. 모의는 외부 시스템의 인공적인 표현입니다. 외부 시스템에 의존하는 코드에 대해 테스트를 실행할 수 있도록 외부 시스템을 시뮬레이션 하는 경우를 제외하고는 외부 시스템을 나타내지 않습니다 . 코드가 실제의 조롱되지 않은 시스템
Robert Harvey

8
다시 말해, 모의는 대체 구현입니다. 그렇기 때문에 실제 구현을위한 스탠드로 모의 객체를 사용할 수 있도록 인터페이스를 프로그래밍했습니다. 다시 말해, 모의는 실제 구현 에서 분리 되거나 결합되지 않습니다.
Robert Harvey

3
"즉, 메소드가 작동하지 않으면 테스트가 실패해야하지만 구현이 변경 되었기 때문이 아닙니다"라고 항상 사실은 아닙니다. 구현과 테스트를 모두 변경해야하는 상황이 많이 있습니다.
whatsisname

답변:


4
  1. 왜 모의가 공개 / 폐쇄 원칙을 위반하는지 알 수 없습니다. 왜 그렇게 생각하는지 설명해 주시면 우려 사항을 완화 할 수 있습니다.

  2. 내가 생각할 수있는 스텁의 유일한 단점은 일반적으로 모의보다 작성하는 데 더 많은 작업이 필요하다는 것입니다. 각 모의는 실제로 종속 인터페이스의 대체 구현이기 때문에 일반적으로 완전한 (또는 확실하게 완전한)을 제공해야합니다 종속 인터페이스의 구현. 극단적 인 예를 들어, 테스트중인 서브 시스템이 RDBMS를 호출하는 경우 RDBMS 모의는 테스트중인 서브 시스템이 발행 한 것으로 알려진 특정 쿼리에 단순히 응답하여 미리 결정된 테스트 데이터 세트를 생성합니다. 반면에 대체 구현은 완전한 메모리 내 RDBMS이며, 프로덕션 환경에서 사용중인 실제 클라이언트 서버 RDBMS의 단점을 모방해야하는 추가 부담이있을 수 있습니다. (행운 적으로, 우리는 HSQLDB와 같은 것을 가지고 있기 때문에 실제로 그렇게 할 수는 있지만 여전히

  3. 모의에 대한 유용한 사용 사례는 종속 인터페이스가 너무 복잡하여 대체 구현을 작성하지 않거나 모의 객체를 한 번만 작성하고 다시 만지지 않는 경우입니다. 이러한 경우에는 빠르고 더러운 모의를 사용하십시오. 결과적으로 스텁 (대체 구현)에 대한 좋은 사용 사례는 거의 모든 것입니다. 특히 테스트중인 서브 시스템과 장기적인 관계에있는 것으로 예상되는 경우, 대체로 구현할 수있는 대체 구현을 사용하는 것이 좋습니다. 변경 때마다 시험 변경에 따라 서브 시스템의 구현.

추신 : 당신이 언급 한 사람은 programmers.stackexchange.com에있는 다른 테스트 관련 답변 중 하나 입니다.


an alternative implementation would be a full-blown in-memory RDBMS-당신은 반드시 그루터기로 그렇게 멀리 갈 필요는 없습니다.
Robert Harvey

@RobertHarvey, HSQLDB 및 H2를 사용하면 실제로 그렇게 멀지는 않습니다. 그렇게 멀리 가지 않기 위해 반쯤 something은 일을하는 것이 더 어려울 것입니다. 그러나 스스로 결정하기로 결정했다면 먼저 SQL 파서를 작성해야합니다. 물론 모서리를 깎을 수는 있지만 많은 작업이 필요 합니다. 어쨌든, 위에서 말했듯이 이것은 극단적 인 예입니다.
Mike Nakis

9
  1. Open / Closed 원칙은 주로 클래스를 수정하지 않고 클래스의 동작을 변경할 수 있다는 것입니다. 따라서 테스트중인 클래스 내에 모의 컴포넌트 종속성을 주입해도 위반되지 않습니다.

  2. 테스트 복식 (mock / stub)의 문제점은 기본적으로 테스트중인 클래스가 환경과 상호 작용하는 방식에 대한 임의의 가정을한다는 것입니다. 이러한 기대치가 잘못되면 코드를 배포 한 후에 문제가 발생할 수 있습니다. 여유가 있다면 프로덕션 환경과 동일한 제약 조건 내에서 코드를 테스트하십시오. 만약 당신이 할 수 없다면, 가능한 최소한의 가정을하고 시스템의 주변 장치 (데이터베이스, 인증 서비스, HTTP 클라이언트 등) 만 모의 / 스텁하십시오.

IMHO, 이중을 사용해야하는 유일한 유효한 이유는 테스트중인 클래스와의 상호 작용을 기록해야하거나 가짜 데이터를 제공해야하는 경우 (두 기술 모두 가능)입니다. 그러나이를 악용하면 디자인이 잘못되었거나 테스트 구현중인 API에 너무 의존하는 테스트가 반영된다는 점에주의하십시오.


6

참고 : 나는 이 스택에 따라 "구현이없는 클래스, 모니터링 할 수있는 클래스"와 Stub이 "일부 모의, 일명 구현 된 클래스의 실제 동작을 사용함"을 의미하도록 Mock을 정의한다고 가정합니다. 오버플로 질문 .

컨센서스가 스텁을 사용하는 것이라고 생각하는 이유를 잘 모르겠습니다. 예를 들어 Mockito Documentation 의 반대와 같습니다.

평소와 같이 부분 모의 경고를 읽으려고합니다. 객체 지향 프로그래밍은 복잡성을 별도의 특정 SRPy 객체로 나누어 복잡성을 덜 해결합니다. 부분 모의가이 패러다임에 어떻게 맞습니까? 글쎄, 그것은 단지 ... 부분 모의는 복잡성이 동일한 객체에서 다른 방법으로 이동되었다는 것을 의미합니다. 대부분의 경우 이것은 응용 프로그램을 디자인하려는 방식이 아닙니다.

그러나 부분 모의가 편리한 경우는 거의 없습니다. 코드를 다루기 만하면 쉽게 변경할 수 없습니다 (타사 인터페이스, 레거시 코드의 중간 리팩토링 등). 그러나 테스트 중심의 새롭고 효과적인 부분 모의를 사용하지는 않습니다. 설계된 코드.

그 문서는 내가 할 수있는 것보다 더 잘 말합니다. 모의를 사용하면 특정 클래스 만 테스트 할 수 있습니다. 찾고있는 동작을 달성하기 위해 부분 모의가 필요한 경우, 잘못된 작업을 수행했거나 SRP를 위반하는 등의 이유로 코드가 리팩터링 될 수 있습니다. Mocks는 개방형 원칙을 위반 하지 않습니다. 어쨌든 테스트에서만 사용되기 때문에 해당 코드의 실제 변경 사항이 아닙니다. 일반적으로 cglib와 같은 라이브러리에 의해 즉시 생성됩니다.


2
제공된 동일한 SO 질문 (허용 된 답변)에서 이것은 내가 참조하고있는 모의 / 스텁 정의입니다. 모의 객체는 기대치를 정의하는 데 사용됩니다.이 시나리오에서는 메소드 A ()가 이러한 매개 변수와 함께 호출 될 것으로 기대합니다. Mocks는 그러한 기대를 기록하고 확인합니다. 반면에 스텁은 다른 목적을 가지고 있습니다. 기대치를 기록하거나 확인하지 않고 테스트 시나리오를 활용하기 위해“가짜”객체의 동작, 상태를“대체”할 수있게합니다.
Christopher Francisco

2

유효한 테스트 만 개방 / 폐쇄 테스트를 충족하는 것으로 가정하여 문제가 발생할 수 있다고 생각합니다.

중요한 테스트는 인터페이스를 테스트하는 것만 쉽게 알 수 있습니다. 그러나 실제로 내부 작업을 테스트하여 해당 인터페이스를 테스트하는 것이 더 효과적입니다.

예를 들어, "구현은 예외를 던져서는 안된다"와 같은 부정적인 요구 사항을 테스트하는 것은 거의 불가능하다. 해시 맵으로 구현되는 맵 인터페이스를 고려하십시오. 해시 맵이 물건을 다시 해시해야 할 때에도 (해치 질 수 있음) 맵 인터페이스를 던지지 않고 확실하게 만들고 싶습니다. 모든 입력 조합을 테스트하여 인터페이스 요구 사항을 충족하는지 확인할 수 있지만, 우주의 열사보다 더 오래 걸릴 수 있습니다. 대신 캡슐화를 약간 깨뜨리고 더 밀접하게 상호 작용하는 모의를 개발하여 해시 맵이 재 해싱 알고리즘이 발생하지 않도록하는 데 필요한 재 해시를 정확하게 수행하도록하십시오.

Tl / Dr : "책으로"하는 것이 좋지만 푸시가 밀려 올 때 금요일까지 상사의 책상에 제품을 두는 것이 책의 열사병까지 걸리는 도서 별 테스트 스위트보다 더 유용합니다. 적합성을 확인하는 우주.

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