단위 테스트를 위해 C #에서 파일 시스템을 어떻게 모방합니까?


149

단위 테스트를 작성하기 위해 C #에서 파일 시스템을 모방하는 라이브러리 또는 메소드가 있습니까? 현재의 경우 특정 파일이 있는지 확인하고 생성 날짜를 읽는 방법이 있습니다. 앞으로는 그 이상이 필요할 수 있습니다.


1
이것은 stackoverflow.com/questions/664277/…을 포함하여 여러 다른 것의 복제본처럼 보입니다 .
존 손더스


2
@Mitch : 대부분의 경우 파일 시스템에 데이터를 저장하고 단위 테스트를 통해 과정을 실행하는 것으로 충분합니다. 그러나 많은 IO 작업을 실행하는 메서드가 발생했으며 모의 파일 시스템을 사용하여 이러한 메서드에 대한 테스트 환경 설정을 크게 단순화했습니다.
Steve Guidi

나는 그 목적 (그리고 그 이상)을 위해 github.com/guillaume86/VirtualPath 를 작성 했지만 여전히 WIP이며 API는 확실히 변경되지만 이미 작동하며 일부 테스트가 포함됩니다.
Guillaume86

답변:


154

편집 : NuGet 패키지를 설치하십시오 System.IO.Abstractions.

이 답변이 처음 수락되었을 때이 패키지는 존재하지 않았습니다. 아래의 역사적 맥락에 대한 원래 답변이 제공됩니다.

인터페이스를 만들어서 할 수 있습니다.

interface IFileSystem {
    bool FileExists(string fileName);
    DateTime GetCreationDate(string fileName);
}

System.IO.File.Exists () 등을 사용하는 '실제'구현을 작성합니다. 그런 다음 조롱 프레임 워크를 사용하여이 인터페이스를 조롱 할 수 있습니다. 나는 Moq를 추천한다 .

편집 : 누군가가 이것을하고 친절하게 온라인으로 여기에 게시했습니다 .

이 방법을 사용하여 IClock 인터페이스 (시간 흐름을 제어 할 수있는 테스트에 실제로 유용합니다!)에서 DateTime.UtcNow를 조롱하고보다 전통적으로 ISqlDataAccess 인터페이스를 사용했습니다.

또 다른 방법은 TypeMock 을 사용하는 것입니다 . 이렇게하면 클래스에 대한 호출을 가로 채고 스텁 할 수 있습니다. 그러나 이것은 비용이 들며, 실행하기 위해서는 전체 팀의 PC와 빌드 서버에 설치해야하며, mscorlib를 스터브수 없으므로 System.IO.File에서는 작동하지 않을 것입니다 .

또한 특정 방법을 단위로 테스트 할 수 없다는 점을 받아들이고 느리게 실행되는 별도의 통합 / 시스템 테스트 스위트에서 테스트 할 수 있습니다.


1
내 생각에 Matt이 설명하는 인터페이스를 만드는 것이 좋습니다. 나는 당신을 위해 그러한 인터페이스를 생성하는 도구를 작성했습니다.이 클래스는 정적 및 / 또는 봉인 된 클래스 또는 결정적이지 않은 메소드 (클럭 및 난수 생성기)를 조롱 할 때 유용합니다. 자세한 내용은 jolt.codeplex.com 을 참조하십시오.
Steve Guidi

참조 된 기사의 저장소가 예고없이 삭제 / 이동 된 것 같습니다. 그러나 여기에 노력의 nuget 패키지가있는 것으로 보입니다 : nuget.org/packages/mscorlib-mock
Mike-E

Typemock에는 위조 가능한 유형에 대한 제한이 있지만 (2017 년 10 월 현재 현재 버전에서는) File 정적 클래스를 확실히 위조 할 수 있습니다. 방금 직접 확인했습니다.
Ryan Rodemoyer 1

통합 테스트 스위트를 요약 할 수 있습니까?
Ozkan

83

설치 패키지 시스템 IO 요약

가상의 라이브러리가 이제 존재합니다. System.IO.Abstractions 용 NuGet 패키지가 있으며, System.IO 네임 스페이스를 추상화합니다.

또한 작성시에는 부분적으로 만 구현되지만 매우 좋은 시작점이되는 일련의 테스트 도우미 System.IO.Abstractions.TestingHelpers가 있습니다.


3
이미 구축 된 추상화를 중심으로 표준화하는 것이 최선의 방법이라고 생각합니다. 그 도서관에 대해 들어 본 적이 없으므로 많은 관심을 가져 주셔서 감사합니다.
julealgon

PM은 패키지 관리자를 나타냅니다. 열기 ... 도구> NuGet 패키지 관리자> 패키지 관리자 콘솔
thedanotto

11

파일 시스템에서 필요한 것을 정의한 다음 해당 기능에 대한 래퍼를 작성하는 계약을 작성해야 할 것입니다. 그 시점에서 구현을 조롱하거나 스텁 아웃 할 수 있습니다.

예:

interface IFileWrapper { bool Exists(String filePath); }

class FileWrapper: IFileWrapper
{
    bool Exists(String filePath) { return File.Exists(filePath); }        
}

class FileWrapperStub: IFileWrapper
{
    bool Exists(String filePath) 
    { return (filePath == @"C:\myfilerocks.txt"); }
}

5

시스템 네임 스페이스에서 주로 사용되는 유형에 대한 래퍼를 제공 하므로 http://systemwrapper.codeplex.com/ 을 사용하는 것이 좋습니다.


현재이 라이브러리를 사용하고 있으며 FileStream과 같은 것에 대한 추상화에 IDisposable이 포함되어 있지 않다는 것을 발견했습니다. 대체를 찾고 있습니다. 라이브러리에서 스트림을 올바르게 처리 할 수없는 경우 이러한 종류의 작업을 처리하는 데 권장하거나 사용할 수 없습니다.
제임스 네일

1
SystemWrapper의 IFileStreamWrap은 이제 IDisposable을 구현합니다.
tster

systemwrapper는 .netcore와 함께 사용할 경우 이상한 문제가 발생할 것입니다, .NET 프레임 워크 아니라
아딜 H. 라자

3

나는 이것에 대한 다음과 같은 솔루션을 보았습니다.

  • 단위 테스트가 아닌 통합 테스트를 작성하십시오. 이것이 작동하려면 다른 테스트 방해에 대해 걱정하지 않고 물건을 덤프 할 수있는 폴더를 만드는 간단한 방법이 필요합니다. 사용할 테스트 메소드 폴더마다 고유 한 간단한 TestFolder 클래스가 있습니다.
  • 모의 가능한 System.IO.File을 작성하십시오. 그것이 IFile.cs 입니다. 이것을 사용하면 종종 모의 진술을 작성할 수 있음을 입증하는 테스트로 끝나지만 IO 사용량이 적을 때 사용합니다.
  • 추상화 계층을 검사하고 클래스에서 파일 IO를 추출하십시오. 이를위한 인터페이스를 만듭니다. 나머지는 통합 테스트를 사용하지만 매우 작습니다. ioThingie.loadSettings ()와 같이 의도를 작성하십시오.
  • System.IO.Abstractions . 나는 이것을 아직 사용하지는 않았지만, 내가 가지고 놀기에 가장 흥분되는 것입니다.

내가 쓰고있는 것에 따라 위의 모든 방법을 사용하게됩니다. 그러나 대부분의 경우 IO에 도달하는 단위 테스트를 작성할 때 추상화가 잘못되었다고 생각합니다.


4
IFile.cs에 대한 링크가 손상되었습니다.
Mike-E

3

System.IO.AbstractionsSystem.IO.Abstractions.TestingHelpers 를 사용 하면 다음과 같습니다.

public class ManageFile {
   private readonly IFileSystem _fileSystem;
   public ManageFile(IFileSystem fileSystem){

      _fileSystem = fileSystem;
   }

   public bool FileExists(string filePath){}
       if(_fileSystem.File.Exists(filePath){
          return true;
       }
       return false;
   }
}

테스트 클래스에서 MockFileSystem ()을 사용하여 파일을 모방하고 다음과 같이 ManageFile을 설정합니다.

var mockFileSysteme = new MockFileSystem();
var mockFileData = new MockFileData("File content");
mockFileSysteme.AddFile(mockFilePath, mockFileData );
var manageFile = new ManageFile(mockFileSysteme);

2

예를 들어 코드베이스가 이미 고정되어 있기 때문에 코드베이스를 변경할 필요없이 Microsoft Fakes 를 사용하여이를 수행 할 수 있습니다 .

먼저 System.dll 또는 다른 패키지에 대한 가짜 어셈블리생성 한 후 다음과 같이 예상되는 결과를 조롱합니다.

using Microsoft.QualityTools.Testing.Fakes;
...
using (ShimsContext.Create())
{
     System.IO.Fakes.ShimFile.ExistsString = (p) => true;
     System.IO.Fakes.ShimFile.ReadAllTextString = (p) => "your file content";

      //Your methods to test
}

1

.NET 파일 API는 실제로 조롱 될 수있는 인터페이스 또는 확장 가능한 클래스를 기반으로하지 않기 때문에 테스트에서 파일 시스템을 조롱하기가 어렵습니다.

그러나 파일 시스템에 액세스하기위한 자체 기능 계층이있는 경우 단위 테스트에서이를 모방 할 수 있습니다.

조롱의 대안으로 테스트 설정의 일부로 필요한 폴더와 파일을 생성하고 분해 방법에서 삭제하는 것을 고려하십시오.


1

파일 시스템을 어떻게 조롱할지 잘 모르겠습니다. 할 수있는 일은 테스트에 필요한 구조로 폴더 등을 만드는 테스트 픽스처 설정을 작성하는 것입니다. 테스트가 실행 된 후 분해 방법으로 정리할 수 있습니다.

추가 편집 : 이것에 대해 조금 더 생각할 때,이 유형의 메소드를 테스트하기 위해 파일 시스템을 모방하고 싶지는 않습니다. 파일 시스템을 모의하여 특정 파일이 존재하는 경우 true를 반환하고 해당 파일이 존재하는지 확인하는 방법을 테스트 할 때 파일 시스템을 사용하면 아무 것도 테스트하지 않습니다. 파일 시스템을 조롱하는 것은 파일 시스템에 종속 된 메소드를 테스트하려고하지만 파일 시스템 활동이 테스트중인 메소드의 필수 요소가 아닌 경우에 유용합니다.


1

특정 질문에 대답하려면 : 아니요, 파일 I / O 호출 (내가 아는)을 조롱 할 수있는 라이브러리가 없습니다. 즉, 유형을 "적절하게"단위 테스트하려면 유형을 정의 할 때이 제한 사항을 고려해야합니다.

"적절한"단위 테스트를 정의하는 방법에 대한 간단한 참고 사항. 단위 테스트를 통해 알려진 입력을 제공 한 예상 출력 (예외, 메소드 호출 등)을 얻을 수 있는지 확인해야한다고 생각합니다. 이를 통해 단위 테스트 조건을 일련의 입력 및 / 또는 입력 상태로 설정할 수 있습니다. 내가 찾은 가장 좋은 방법은 인터페이스 기반 서비스와 종속성 주입을 사용하여 형식 외부의 각 책임이 생성자 또는 속성을 통해 전달 된 인터페이스를 통해 제공되도록하는 것입니다.

따라서 이것을 염두에두고 질문으로 돌아가십시오. 나는 단순히 mscorlib 파일 시스템 메소드의 정면에 IFileSystemService대한 FileSystemService구현 과 함께 인터페이스를 작성하여 파일 시스템 호출을 조롱했습니다 . 그런 다음 내 코드 IFileSystemService는 mscorlib 유형 대신 오히려 를 사용합니다 . 이를 통해 FileSystemService응용 프로그램이 실행 중일 때 표준을 연결할 수 있습니다 .IFileSystemService 단위 테스트를 있습니다. 응용 프로그램 코드는 실행 방식에 관계없이 동일하지만 기본 인프라를 통해 해당 코드를 쉽게 테스트 할 수 있습니다.

mscorlib 파일 시스템 개체 주위에서 래퍼를 사용하는 것은 고통 스럽지만 이러한 특정 시나리오에서는 테스트가 훨씬 쉽고 안정적으로 진행되므로 추가 작업을 수행 할 가치가 있습니다.


1

테스트를 위해 인터페이스를 만들고 조롱하는 것이 가장 깨끗한 방법입니다. 그러나 대안으로 Microsoft Moles 프레임 워크를 살펴볼 수 있습니다 .


0

일반적인 솔루션은 일부 추상 파일 시스템 API (예 : Apache Commons VFS for Java)를 사용합니다. 모든 응용 프로그램 논리는 API를 사용하고 단위 테스트는 스텁 구현 (메모리 내 에뮬레이션 등)으로 실제 파일 시스템을 조롱 할 수 있습니다.

C #의 경우 유사한 API가 있습니다. NI.Vfs 는 Apache VFS V1과 매우 유사합니다. 로컬 파일 시스템과 메모리 내 파일 시스템 모두에 대한 기본 구현이 포함되어 있습니다 (마지막 시스템은 상자에서 단위 테스트에 사용될 수 있음).


-1

우리는 현재 독점 데이터 엔진을 사용하고 있으며 API는 인터페이스로 노출되지 않으므로 데이터 액세스 코드를 거의 단위 테스트 할 수 없습니다. 그런 다음 Matt와 Joseph의 접근 방식도 함께했습니다.


-2

나는 Jamie Ide의 응답으로 갈 것입니다. 작성하지 않은 것을 조롱하려고하지 마십시오. 봉인 클래스, 비가 상 메소드 등 알지 못하는 모든 종속성이 있습니다.

또 다른 방법은 적절한 방법으로 적절한 방법을 래핑하는 것입니다. 예를 들어 File 메소드에 액세스 할 수 있지만 FileMrapper라는 클래스를 만들 수 있습니다.

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