모의 콘크리트 클래스-권장하지 않음


11

방금 구체적인 클래스를 조롱하는 것이 권장되지 않는 몇 가지 이유를 설명하는 "Growing Object-Oriented Software"책을 읽었습니다.

MusicCentre 클래스의 단위 테스트 샘플 코드는 다음과 같습니다.

public class MusicCentreTest {
  @Test public void startsCdPlayerAtTimeRequested() {
    final MutableTime scheduledTime = new MutableTime();
    CdPlayer player = new CdPlayer() { 
      @Override 
      public void scheduleToStartAt(Time startTime) {
        scheduledTime.set(startTime);
      }
    }

    MusicCentre centre = new MusicCentre(player);
    centre.startMediaAt(LATER);

    assertEquals(LATER, scheduledTime.get());
  }
}

그리고 그의 첫 번째 설명 :

이 접근법의 문제점은 오브젝트 간의 관계를 내재적으로 유지한다는 것입니다. 모의 객체를 이용한 테스트 주도 개발의 목적은 객체 간의 관계를 발견하는 것임을 분명히 알았기를 바랍니다. 하위 클래스를 작성하면 도메인 코드에 객체의 메소드만이 그러한 관계를 보이게 할 것이 없습니다. 따라서이 관계를 지원하는 서비스가 다른 곳과 관련이 있는지 확인하기가 어려워 다음에 수업에 참여할 때 분석을 다시 수행해야합니다.

그가 말할 때 그가 무엇을 의미하는지 정확히 알 수 없습니다.

따라서이 관계를 지원하는 서비스가 다른 곳과 관련이 있는지 확인하기가 어려워 다음에 수업에 참여할 때 분석을 다시 수행해야합니다.

서비스가 MusicCentre의 메소드에 해당한다는 것을 이해합니다 startMediaAt.

"어딘가에"는 무슨 뜻입니까?

전체 발췌문은 다음과 같습니다. http://www.mockobjects.com/2007/04/test-smell-mocking-concrete-classes.html


그의 인용문에서 그가 무엇을 의미하는지 알 수 없었기 때문에 그의 블로그에 의견을 추가했습니다.
oligofren의

@oligofren 정말 대단한 수수께끼입니다 :) ...
Mik378

답변:


6

이 글의 저자는 멤버 클래스 사용에 대한 인터페이스 사용을 장려하고 있습니다.

It turns out that my MusicCentre object only uses the starting and stopping methods on the CdPlayer, the rest are used by some other part of the system. I'm over-specifying my MediaCentre by requiring it to talk to a CdPlayer, what it actually needs is a ScheduledDevice.

그가 나중에 다시 발견하는 것에 대해 걱정하는 관계는 MediaCentre 클래스에 모든 CdPlayer 객체가 필요하지 않다는 사실입니다. 그의 주장은 인터페이스 (아마도 단지 시작 | 중지로 제한됨)를 사용함으로써 상호 작용이 실제로 무엇인지 이해하기 쉽다는 것입니다.

"어딘가에"는 단순히 다른 개체가 비슷하게 제한된 관계를 가질 수 있으며 전체 멤버 개체가 필요하지 않음을 의미합니다. 인터페이스를 통해 래핑 된 기능의 하위 집합이면 충분합니다.

모든 잠재적 기능을 분석 할 때 클레임이 더 이해되기 시작합니다.

  • 스타트
  • 중지
  • 중지
  • 기록
  • 랜덤 플레이 순서
  • 노래의 시작 부분 샘플 트랙
  • 샘플 트랙, 노래의 임의 샘플
  • 미디어 정보를 제공
  • ...

이제 "나는 단지 시작과 중지가 필요하다"는 그의 주장이 더 의미가있다. 인터페이스 대신 콘크리트 멤버 객체를 사용하면 미래의 개발자에게 실제로 필요한 사항 에 대한 명확성이 떨어집니다 . CdPlayer 내의 다른 모든 기능에 대해 MediaCentre에서 단위 테스트를 실행하면 "무정의"상태에 속하기 때문에 테스트 작업이 낭비됩니다. 이 경우 Record함수가 작동하지 않으면 필요하지 않으므로 실제로 신경 쓰지 않습니다. 그러나 미래의 관리자는 코드를 기반으로 작성된 것을 반드시 알 필요는 없습니다.

궁극적으로 저자의 전제는 필요한 것만 사용하고 미래의 관리자에게 이전에 필요한 것을 명확하게하는 것입니다. 목표는 후속 유지 보수 중 코드 모듈 재 작업 / 재분석을 최소화하는 것입니다.


이 위대한 답변에 감사드립니다. 그러나 "다른 모든 기능에 대해 단위 테스트를 실행하는 것은"무정의 "상태에 속하기 때문에 테스트 노력을 낭비하는 것입니다." "다른 기능들 각각에 대한 모의 객체를 생성하는 것은"무관심 "상태에 속하기 때문에 테스트 노력을 낭비 하는가?"
Mik378

@ Mik378-예, 정확히 내가 얻은 것입니다. 방금 다르게 표현했습니다. 그리고 나는 그것을 더 명확하게하기 위해 대답을 업데이트했습니다.

그러나 "단위 테스트 실행"이라는 용어가 혼란 스럽다는 것을 알았습니다. 즉, MusicCentre는 공동 작업자를 단위 테스트하려고하지만 실제로는 자신의 OWN 서비스를 단위 테스트하기 위해 공동 작업자를 MOCKS합니다. 그건 그렇고, 나는 이제 의미를 이해합니다 :)
Mik378

@ Mik378-우리는 같은 것을 말하고 있으며, 그렇게하기 위해 아마도 정확한 용어보다 덜 사용하고 있습니다. 혼란에 대한 사과.

4

따라서이 관계를 지원하는 서비스가 다른 곳과 관련이 있는지 확인하기가 어려워 다음에 수업에 참여할 때 분석을 다시 수행해야합니다.

그것에 대해 많이 생각한 후에이 인용문에 대한 가능한 해석을 얻습니다.

인용 된 "서비스"는 "예약 사실"에 해당합니다. 이것은 "ScheduledDevice"라는 이름이 붙은 "focused-on-one-role"인터페이스로 표현되거나 인터페이스에 의존하지 않는 구체적인 메소드 구현으로 암시 적으로 표현 될 수 있습니다.

위의 샘플에서 스케줄링은이라는 전체 기능을 갖춘 전체 객체로 표현됩니다 CDPlayer. 따라서, 그것은 여전히 MusicCentre"스케줄의 사실"과 묵시적 관계로 이어진다 .

우리가 구체적인 클래스를 주입하고 그것들을 높은 수준의 객체에 조롱하기 시작한다면; 이러한 개체를 테스트하려면 주입 된 각 "콘크리트"개체를 분석하여 숨겨져 있기 때문에 MOCK해야하는 특정 관계를 나타내는 지 확인해야합니다 (암시 적). 반대로, 인터페이스를 통한 항상 코딩은 개발자가 고급 객체가 어떤 종류의 관계를 제공할지 직접 파악할 수있게 해주므로 단위 테스트를 분리하기 위해 조롱해야 할 기능을 감지 할 수 있습니다.


나는 당신이 지금 그것을 가지고 있다고 생각합니다. 불행히도 귀하의 의견에 대한 알림을받지 못했습니다.
Steve Freeman

3

여기서 의미하는 서비스는 CDPlayer.scheduleToStartAt ()입니다. 그것이 바로 MediaCentre가 부르는 것, 즉 작동해야하는 협력자입니다. MediaCentre는 테스트중인 개체입니다.

아이디어는 구현 클래스가 아니라 MediaCentre가 의존하는 것을 명시 적으로 만들면 해당 종속성 역할에 이름을 부여하고 이야기 할 수 있다는 것입니다. MediaCentre가 알아야 할 것은 ScheduledDevices와 통신한다는 것입니다. 나머지 시스템이 변경되면 기능이 변경되지 않는 한 MediaCentre를 변경할 필요가 없습니다.

도움이 되나요?


(이 위대한 기사의 저자 :)) 내가 해석하고 싶었던 것은 다음과 같은 문장이었다. 클래스와 함께 " 어떤 종류의 분석입니까? 어떤 객체의 메소드가 관계를 구현해야하는지 감지한다는 사실이 명확하게 숨겨져 있기 때문에 관계를 구현해야합니까?
Mik378
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.