2015-10-21 4 views
4

У меня есть FileSystemWatcher просмотр каталога изменений, и когда в нем есть новый XML-файл, он анализирует этот файл и что-то делает с ним.Unit-testing FileSystemWatcher: как программно запускать измененное событие?

У меня есть несколько примеров XML-файлов в моем проекте, которые я использую для тестирования модулей для синтаксического анализатора, который я написал.

Я ищу способ использовать образцы XML-файлов также для тестирования FileSystemWatcher.

Возможно ли запрограммировать создание события (каким-то образом связанного с файлом XML), чтобы вызвать событие FSW.Changed?

+0

Не может открыть файл и добавить некоторые испытания в файл XML, например, Добавьте комментарий, а затем верните его на диск. – Don

+0

. Пожалуйста, поделитесь кодом для FSW, который вы хотите протестировать, и попыткой модульного тестирования. – Yogi

+1

Во-первых, вы можете создать макет объекта для FileSystemWatcher и передать его в свой класс, а затем вызвать измененное событие от вашего макета.Другой вариант - вы можете создать класс mock, полученный из FileSystemWatcher, и переопределить измененный метод, как вы хотите, и передать его в свой класс для тестирования. Другой вариант, в вашем тесте, когда ваш код просматривает изменения файла, копирует и вставляет реальный файл в ваш каталог в параллельной задаче. – mecek

ответ

7

Я думаю, что вы здесь ошибаетесь.

Вам не следует пытаться напрямую протестировать класс FileSystemWatcher (вы не можете - у вас нет контроля над ним!). Вместо этого, вы можете попробовать следующее:

1) Написать класс-обертку для FileSystemWatcher класса, который только делегаты его функциональность к экземпляру FileSystemWatcher. Вот пример с одним методом и одно событие, добавить больше членов в соответствии с требованиями:

public class FileSystemWatcherWrapper 
{ 
    private readonly FileSystemWatcher watcher; 

    public event FileSystemEventHandler Changed; 

    public FileSystemWatcherWrapper(FileSystemWatcher watcher) 
    { 
     this.watcher = watcher 
     watcher.Changed += this.Changed; 
    } 

    public bool EnableRaisingEvents 
    { 
     get { return watcher.EnableRaisingEvents; } 
     set { watcher.EnableRaisingEvents = value; } 
    } 
} 

(Обратите внимание, как экземпляр FileSystemWatcher передается в конструктор класса, вы можете создать новый экземпляр на лету, а не когда обертка строится)

2) Extract интерфейс для класса:

public interface IFileSystemWatcherWrapper 
{ 
    event FileSystemEventHandler Changed; 
    bool EnableRaisingEvents { get; set; } 
} 

//and therefore... 

public class FileSystemWatcherWrapper : IFileSystemWatcherWrapper 

3) Сделайте ваш класс зависит от интерфейса:

public class TheClassThatActsOnFilesystemChanges 
{ 
    private readonly IFileSystemWatcherWrapper fileSystemWatcher; 

    public TheClassThatActsOnFilesystemChanges(IFileSystemWatcherWrapper fileSystemWatcher) 
    { 
     this.fileSystemWatcher = fileSystemWatcher; 

     fileSystemWatcher.Changed += (sender, args) => 
     { 
      //Do something... 
     }; 
    } 
} 

4) Во время инициализации приложения, создать экземпляр класса с использованием любого впрыском зависимостей, или просто сделать инъекцию бедняка:

var theClass = new TheClassThatActsOnFilesystemChanges(
    new FileSystemWatcherWrapper(new FileSystemWatcher())); 

5) Теперь идти вперед и писать тесты для TheClassThatActsOnFilesystemChanges путем создания издеваться над IFileSystemWatcherWrapper, который запускает события по вашей воле! Для этого вы можете использовать любой из насмехающийся движок, например Moq.

Суть:

Если у вас есть зависимость от класса, который вы не контролируете и/или не могут быть осмысленно протестированы, написать обертку вокруг него с соответствующим интерфейсом, и зависят от интерфейса. Ваша обертка настолько тонкая, что на самом деле не больно, если вы не можете ее протестировать, а ваши классы клиентов теперь могут быть правильно протестированы.

+0

FSW - хитрый зверь, чтобы точно высмеивать. Обязательно включайте латентность, повторяющиеся уведомления, блокировки из другого программного обеспечения и отсутствующие уведомления в плане тестирования. Возможно, есть и другие оговорки, которые мне тоже не хватает. – Mitch

+0

Вы связываете события в примере? Кажется, я не могу заставить события так цепляться. Есть что-то, что я могу пропустить? – TiQP

+1

Спасибо! Исправьте небольшую опечатку - добавьте «this.watcher = watcher;» в конструкторе FileSystemWatcherWrapper. –

1

Просто проистекает из FileSystemWatcher и добавить то, что вам нужно интерфейс:

public interface IFileSystemWatcherWrapper : IDisposable 
{   
    bool EnableRaisingEvents { get; set; } 
    event FileSystemEventHandler Changed; 
    //... 
} 

public class FileSystemWatcherWrapper : FileSystemWatcher, IFileSystemWatcherWrapper 
{ 
    public FileSystemWatcherWrapper(string path, string filter) 
     : base(path, filter) 
    { 
    } 
}