2017-10-31 23 views
1

Linux에서 USB 장치 도착 및 제거를 모니터링하는 클래스를 만들려고합니다. Linux에서 USB 장치는 /dev/bus/usb 아래 장치 파일로 표시되며 이러한 이벤트에 대한 응답으로 생성/삭제됩니다.System.IO.Abstractions의 FileSystemWatcher를 사용하여 모의 파일 시스템을 모니터하는 방법은 무엇입니까?

이러한 이벤트를 추적하는 가장 좋은 방법은 FileSystemWatcher입니다. 클래스를 테스트 할 수있게 만들려면 System.IO.Abstractions을 사용하고 IFileSystem 인스턴스를 생성하는 동안 클래스에 삽입해야합니다. 내가 원하는 것은 FileSystemWatcher처럼 행동하지만 실제로는 실제 파일 시스템이 아니라 주입 된 IFileSystem에 대한 변경 사항을 모니터하는 것입니다.

FileSystemWatcherBaseFileSystemWatcherWrapperSystem.IO.Abstractions에서 확인하는 방법을 잘 모르겠습니다. 순간 내가 가진이 (내가 아는 이는 잘못된 것입니다) :

System.IO.Abstractions 아직이 기능을 지원하지 않는 것 사실에 비추어
public DevMonitor(
    [NotNull] IFileSystem fileSystem, 
    [NotNull] IDeviceFileParser deviceFileParser, 
    [NotNull] ILogger logger, 
    [NotNull] string devDirectoryPath = DefaultDevDirectoryPath) 
{ 
    Raise.ArgumentNullException.IfIsNull(logger, nameof(logger)); 
    Raise.ArgumentNullException.IfIsNull(devDirectoryPath, nameof(devDirectoryPath)); 

    _fileSystem = fileSystem ?? throw new ArgumentNullException(nameof(fileSystem)); 
    _deviceFileParser = deviceFileParser ?? throw new ArgumentNullException(nameof(deviceFileParser)); 
    _logger = logger.ForContext<DevMonitor>(); 
    _watcher = new FileSystemWatcherWrapper(devDirectoryPath); 
} 
+0

downvote가 무엇인지 물어볼 수 있습니까? – Tagc

+0

나는 그것이 가능하지 않다고 생각한다. FileSystemWatcher 클래스는 전혀 확장 할 수 없으며 (유용한 가상 메서드조차 가지고 있지 않습니다.) 대신 FileSystemWatcher는'Created' 등의 이벤트가있는 인터페이스 뒤에 있고, 유닛 테스트에서는 수동으로 이벤트를 실행합니다. 그래서'IFileSystem'에 디렉토리를 추가 한 후 - 해당 이벤트를 직접 실행하십시오. – Evk

+0

그건 한 가지 방법이긴하지만 그 일에 의지하지 않기를 바랬습니다. 필자는 그들에게'FileSystemWatcher'를 직접 확장 할 것을 기대하지는 않았지만, 제공된'IFileSystem'이 실제인지 모의인지를 검사하는 공장의 IFileSystem => IFileSystemWatcher' 라인을 따라 무언가를 가지고있을 수도 있습니다. 실제라면, 표준'FileSystemWatcher'를 래퍼 (wrapper)로 반환하십시오. 모의 파일 인 경우 모의 파일 시스템의 변경 사항을 모니터링하는 사용자 정의 클래스를 반환합니다. – Tagc

답변

1

, 나는이와 함께 갔다 :

가 나는 IWatchableFileSystem 정의 IFileSystem를 확장 인터페이스 :

/// <summary> 
/// Represents a(n) <see cref="IFileSystem" /> that can be watched for changes. 
/// </summary> 
public interface IWatchableFileSystem : IFileSystem 
{ 
    /// <summary> 
    /// Creates a <c>FileSystemWatcher</c> that can be used to monitor changes to this file system. 
    /// </summary> 
    /// <returns>A <c>FileSystemWatcher</c>.</returns> 
    FileSystemWatcherBase CreateWatcher(); 
} 

생산을 위해 내가 WatchableFileSystem으로이를 구현 :

/// <inheritdoc /> 
public sealed class WatchableFileSystem : IWatchableFileSystem 
{ 
    private readonly IFileSystem _fileSystem; 

    /// <summary> 
    /// Initializes a new instance of the <see cref="WatchableFileSystem" /> class. 
    /// </summary> 
    public WatchableFileSystem() => _fileSystem = new FileSystem(); 

    /// <inheritdoc /> 
    public DirectoryBase Directory => _fileSystem.Directory; 

    /// <inheritdoc /> 
    public IDirectoryInfoFactory DirectoryInfo => _fileSystem.DirectoryInfo; 

    /// <inheritdoc /> 
    public IDriveInfoFactory DriveInfo => _fileSystem.DriveInfo; 

    /// <inheritdoc /> 
    public FileBase File => _fileSystem.File; 

    /// <inheritdoc /> 
    public IFileInfoFactory FileInfo => _fileSystem.FileInfo; 

    /// <inheritdoc /> 
    public PathBase Path => _fileSystem.Path; 

    /// <inheritdoc /> 
    public FileSystemWatcherBase CreateWatcher() => new FileSystemWatcher(); 
} 
을 내 단위 테스트 클래스 내에서

내가 내 테스트에서 주장 &를 배열에 사용할 수있는 속성으로 MockFileSystemMock<FileSystemWatcherBase>를 노출 MockWatchableFileSystem로 구현 :

private class MockWatchableFileSystem : IWatchableFileSystem 
{ 
    /// <inheritdoc /> 
    public MockWatchableFileSystem() 
    { 
     Watcher = new Mock<FileSystemWatcherBase>(); 
     AsMock = new MockFileSystem(); 

     AsMock.AddDirectory("/dev/bus/usb"); 
     Watcher.SetupAllProperties(); 
    } 

    public MockFileSystem AsMock { get; } 

    /// <inheritdoc /> 
    public DirectoryBase Directory => AsMock.Directory; 

    /// <inheritdoc /> 
    public IDirectoryInfoFactory DirectoryInfo => AsMock.DirectoryInfo; 

    /// <inheritdoc /> 
    public IDriveInfoFactory DriveInfo => AsMock.DriveInfo; 

    /// <inheritdoc /> 
    public FileBase File => AsMock.File; 

    /// <inheritdoc /> 
    public IFileInfoFactory FileInfo => AsMock.FileInfo; 

    /// <inheritdoc /> 
    public PathBase Path => AsMock.Path; 

    public Mock<FileSystemWatcherBase> Watcher { get; } 

    /// <inheritdoc /> 
    public FileSystemWatcherBase CreateWatcher() => Watcher.Object; 
} 

마지막으로, 내 클라이언트 클래스에서 내가 할 단지 수 있습니다 :

public DevMonitor(
    [NotNull] IWatchableFileSystem fileSystem, 
    [NotNull] IDeviceFileParser deviceFileParser, 
    [NotNull] ILogger logger, 
    [NotNull] string devDirectoryPath = DefaultDevDirectoryPath) 
{ 
    // ... 
    _watcher = fileSystem.CreateWatcher(); 

    _watcher.IncludeSubdirectories = true; 
    _watcher.EnableRaisingEvents = true; 
    _watcher.Path = devDirectoryPath; 
} 

는 테스트 중에 클라이언트 MockFileSystem을 감싸고 FileSystemWatcherBase의 모의 인스턴스를 반환하는 IWatchableFileSystem 가져옵니다. 프로덕션 중에는 FileSystem을 랩핑하고 FileSystemWatcher의 고유 인스턴스를 생성하는 IWatchableFileSystem이 생성됩니다.