2012-01-07 3 views
6

나는 유닛 닷넷 System.IO 클래스에 대한 호출을 조롱 테스트 가능한 코드를 생성 할, 그래서 난 정말 단위 테스트 대신 파일 시스템에 따라 할 수 있습니다. SystemWrapper 클래스를 사용하여 BCL 클래스를 랩핑합니다. .Net IO 클래스를 사용하여 테스트 가능한 코드를 만드는 방법은 무엇입니까?

나는 파일이 존재하는지 확인하기 위해 노력하고 간단한 예제를 얻기 위해 노력하고 있어요.

내가 겪고있는 문제는 종속성을 인스턴스화 (StructureMap 통해) 때문에 전달할 수있는 생성자 매개 변수를 알고 있어야하며, 그 시간에 사용할 수 없게됩니다. 기본 생성자가 없습니다.

샘플 코드 :

// don't want to create dependency here like so 
//IFileInfoWrap fileInfoWrap = new FileInfoWrap(filename); 

// using service locator (anti-pattern?!) since it can't be 
// injected in this class 
var fileInfoWrap = ObjectFactory.GetInstance<IFileInfoWrap>(
    new ExplicitArguments(new Dictionary<string, object> 
    { 
     {"fileName", filename} 
    })); 

Console.WriteLine("File exists? {0}", fileInfoWrap.Exists); 

내가 좋아하지 않는 것은 종속성이 주입되지 않는 것입니다, ObjectFactory를 여기 안 (하지만이를 만드는 다른 방법을 참조). ExplicitArguments가 지저분하고 argument-name이 마술 문자열입니다.

ObjectFactory.Initialize(x => 
{ 
    x.Scan(scan => 
    { 
     scan.AssembliesFromPath("."); 
     scan.RegisterConcreteTypesAgainstTheFirstInterface(); 
     scan.WithDefaultConventions(); 
    }); 

    // use the correct constructor (string instead of FileInfo) 
    x.SelectConstructor(() => new FileInfoWrap(null as string)); 

    // setting the value of the constructor 
    x.For<IFileInfoWrap>() 
     .Use<FileInfoWrap>() 
     .Ctor<string>("fileName") 
     .Is(@"."); 
}); 
: 날이 StructureMap의 설정 클래스를 작동하도록하기 위해

나는 (내가 너무이 그것을 설정하는 올바른 방법으로하지 않을 수 StructureMap 시작) 사용할 EXPLICT하는 생성자 알 필요가있다

누구나 System.IO 클래스에 대해 테스트 할 수있는 코드를 만드는 더 좋은 솔루션을 찾았습니까? 문제의 일부가 System.IO 클래스의 디자인에 있음을 알고 있습니다.

+3

SystemWrapper 대부분 매우 새는 추상화가 포함되어 있습니다. Streams, TextWriter, TextReader 등에 대해 IO를 모델링하는 것이 훨씬 쉽고 쉬울 것입니다.이 클래스들은 이미 추상적이어서 SystemWrapper의 필요성을 완전히 제거합니다. 스트림 –

+0

또 다른 투표가 있기 때문에 원래의 클래스가 작동하는 방식하지만, 인터페이스와 멋진 래퍼로는 여전히 막 다른 골목을 보인다이다. 예를 들어 FileInfo 객체의 배열을 반환하면 올바르게 조롱 될 수 없습니다. 기존 클래스를 모방하지 않아도되는 좀 더 단순화 된 래퍼를 롤링하면서 더 많은 작업을 수행하면 IMHO라는 실행 가능한 솔루션으로 이어집니다. –

+0

SystemWrapper 나의 연구 결과에 대한 –

답변

5

나는 매우 성공적으로 사용했던 접근 방법은 System.IO에서 발견되는 유형과 FCL의 다른 부분에 대한 내 자신의 프록시 유형을 출시하는 것입니다. 예 : System.IO.File에 의존하고 싶습니다. System.IO.Proxies 라이브러리를 만들고 구체적인 유형 File과 인터페이스 IFile을 추가합니다. 인터페이스 IFile 내가 System.IO.File에서 필요로하고 구체적인 유형 System.IO.File에 메소드 호출을 전달 이외의 아무것도하지 않고하여 해당 구성원을 구현하는 모든 사람에 해당 멤버를 노출합니다. System.IO.Proxies은 단위 테스트 및 코드 적용 대상에서 제외됩니다. 내 소모적 인 어셈블리에서는, 나는 System.IO.Proxies에만 의존하고, 구체적으로는 IFile에 의존한다. 이렇게하면이 종속성을 쉽게 모방하고 소비하는 어셈블리에 대해 100 % 코드 범위를 확보 할 수 있습니다.

(이것은 내 more general answer 이전 질문의 맞춤형 버전입니다 있습니다.)

+0

네, 그게 제가 끝난 길입니다. 예를 들어 전화를 위임 할 수 있습니다. System.IO.FileInfo를 별도의 클래스로 만듭니다. 자신의 프록시를 롤링하는 것은 그것이 BCL 클래스에서 필요한 기능과 함께 성장할 수 물론 꽤 작업이 될 수있는 각 클래스에 대한 프록시를 만들 필요가 없습니다. 또한 다른 형식 (FileInfo)이 반환되면 필요한 모든 특성이 프록시 (이름, 전체 이름, 길이)에 만들어 져야합니다. 이 문제는 이미 '해결 된'것이므로 모든 사람을위한 프록시를 이미 피할 수 있습니다. –

+0

동일한 접근법을 꽤 성공적으로 사용했습니다. 대개 _File_과 같은 클래스의 모든 메서드/속성/이벤트가 필요하지는 않습니다. 그리고 소수를 위해서는 그러한 래퍼를 작성하는 것이 정말 쉽습니다. –

관련 문제