5

어쩌면 의존성 주입 및 테스트에 대한 이해가 부족하다는 것을 보여줄 수는 있지만 인터페이스를 구현하지 않는 클래스에서 종속성 주입을 사용하면 테스트에 전혀 도움이되는 방법을 이해할 수 없습니까?인터페이스를 제공하지 않더라도 엔터프라이즈 라이브러리에 대한 종속성을 테스트하는 코드는 무엇입니까?

예를 들어 Enterprise Library 5.0 설명서에서는 Unity 컨테이너를 사용하여 인스턴스를 만드는 방법에 대해 설명합니다. 이 기능은 "테스트 가능성 : 종속성 주입 스타일을 사용할 때 클래스를 종속성에서 격리하는 것은 쉽지 않습니다."라고 설명합니다. MSDN

단위 테스트 픽스처에 어떻게 사용합니까? 이 예제는 인터페이스가 아닌 클래스로 매개 변수를 가진 생성자를 가지고 있습니다.

public class TaxCalculator 
{ 
    private ExceptionManager _exceptionManager; 
    private LogWriter _logWriter; 

    public TaxCalculator(ExceptionManager em, LogWriter lw) 
    { 
    this._exceptionManager = em; 
    this._logWriter = lw; 
    } 
} 

답변

9

"엔터 프라이즈 라이브러리 코드을 테스트하려면 어떻게합니까?"라는 질문에 대답하려면 다음을 수행하십시오. 다른 사람들의 물건을 테스트하는 것은 다른 사람들의 일입니다. Enterprise Library 또는 기타 타사 라이브러리의 모든 인터페이스 또는 추상화는 사용자가 아닌 자신의 추상화 목적을 위해 존재합니다.

응용 프로그램의 요구 사항 (로깅, 캐싱, 암호화 등)을 설명하는 자체 인터페이스를 정의한 다음 Enterprise Library (또는 다른 타사 라이브러리)를 사용하여 인터페이스를 구현하는 어댑터를 작성해야합니다. . 이 연습은 Dependency Inversion Principle으로 알려져 있습니다.

이런 식으로 설계된 자신의 코드를 테스트하려면 유닛/구성 요소 레벨 테스트를 위해 자신이 정의한 인터페이스 (예 : IMyOwnLogger)에 대해 Test Double을 사용하면됩니다. 타사 라이브러리에 맞게 작성한 어댑터를 테스트하려면 통합 테스트를 작성하십시오. 모든 기능이 함께 작동하는지 테스트하려면 UI 또는 피하로 앱을 구동하는 수락 테스트를 작성합니다.

이보기에 대한 자세한 내용은 내 기사 "TDD Best Practices: Don't Mock Others"을 확인하십시오.

+0

필자는 Enterprise Library를 테스트하지 않고 Enterprise Library에 의존하는 자체 코드를 반영하기 위해 제목을 변경했습니다. –

+0

외부 의존성에 비추어 자신의 코드를 테스트하는 방법을 명시 적으로 말하기위한 대답을 업데이트했습니다. –

+0

응용 프로그램의 요구 사항을 설명하는 자체 인터페이스 (예 : 로깅)를 정의하는 것이 좋습니다. 인프라를 비즈니스 코드와 분리하는 것은 좋습니다. 그러나 멋진 프레임 워크 기능을 잃고 다른 추상화 수준을 추가하고 최적화 및 성능을 잃어 버리는 것은 분명히 좋지 않습니다. –

4

구현 대신 추상화를 사용하는 것이 좋습니다. 그러나 추상화는 항상 인터페이스가 아닙니다. 그것은 추상적 인 클래스 일 수 있습니다. 당신이 단위 테스트를 수행하지 않으면, 내가 어떤 문제가 아닌 추상적 인 매개 변수를 전달하는 표시되지 않습니다

Mock<LogWriter> logWriter = new Mock<LogWriter>(); 
TaxCalculator calc = new TaxCalculator(logWriter.Object); 

때문에 :

public abstract class LogWriter 
{ 
    public abstract void Write(string message); 
} 

그래서 추상 클래스의 모형을 만드는 문제가 없습니다 YAGNI 원칙의 ExceptionManager의 다른 구현이 필요하지 않다면 왜 그 위에 추상화를 만들어야합니까? 그러나 TDD를한다면 적어도 두 가지 구현 클래스가 필요합니다. 하나의 실제와 하나의 모의/스텁.

btw service locator anti-pattern과 조심하십시오.

업데이트 : 기존 클래스 인 Microsoft.Practices.EnterpriseLibrary를 언급하지 않았다 (필자가 싫어함). Microsoft.Practices 팀의 또 다른 디자인 실패라고 생각합니다. 인터페이스/기본 클래스를 구현하지 않는 '봉인 된'ExceptionManager 클래스를 작성하면 테스트 가능성이 없어집니다.

+0

타사 라이브러리의 추상화는 자체 용도로 사용되며 추상화를 제공하지 않습니다. 또한 Enterprise Library는 sealed 키워드 사용에 대한 완벽한 시나리오 일 수 있습니다. P & P는 항상 EL이 직접적으로 사용되는 것이 아니라 코드 작성의 모범이 될 것이라고 말했습니다. 그들은 사람들이 물건을 확장하고 이후 버전에서 디자인을 변경할 때 불평하지 않기를 바랍니다. –

+0

예를 들어, log4net의 ILog는 사용하기 위해 추상화를 제공하지 않습니까? –

+0

원한다면 그 말을 과장으로 사용하십시오. 서로 다른 소프트웨어 공급 업체는 여러 가지 이유로 인터페이스를 포함합니다. 때때로 인터페이스는 벤더의 테스트 방법론의 부산물로 존재합니다. 다른 때에는 높은 수준의 구성 요소가 의존하는 여러 구현이있을 수 있습니다. 일부 공급 업체는 공개 인터페이스를 수정하지 않고도 미래의 설계 변경을 허용하기 위해 인터페이스를 솔기로 제공 할 수 있습니다. 그리고 그렇습니다. 일부는 인터페이스를 제공하여 모든 것을 다룰 수있는 추상화라고 생각합니다. 그럼에도 불구하고, 당신은 당신 자신의 디자인 내에서 그들을 의지해서는 안됩니다. –

3

클래스가 sealed이 아닌 한, 유능한 조롱 프레임 워크는 조롱 된 인터페이스 구현과 똑같이 작동하는 서브 클래스를 만들 수 있습니다. 구체적인 클래스에 의존 할 때 더 많은 고려 사항이 있습니다. sealed 메소드는 여전히 지정된 클래스에서 실행될 것입니다. 그러나 일반적으로은 인터페이스에 따라 다릅니다.

관련 문제