Search code examples
c#eventsfilesystemwatcher

How do I write a unit test that relies on file system events?


I have the following code that I'd like to test:

public class DirectoryProcessor
{
    public string DirectoryPath
    {
        get;
        set;
    }

    private FileSystemWatcher watcher;

    public event EventHandler<SourceEventArgs> SourceFileChanged;

    protected virtual void OnSourceFileChanged(SourceEventArgs e)
    {
        EventHandler<SourceEventArgs> handler = SourceFileChanged;
        if(handler != null)
        {
            handler(this, e);
        }
    }

    public DirectoryProcessor(string directoryPath)
    {
        this.DirectoryPath = directoryPath;
        this.watcher = new FileSystemWatcher(directoryPath);
        this.watcher.Created += new FileSystemEventHandler(Created);
    }

    void Created(object sender, FileSystemEventArgs e)
    {
        // process the newly created file
        // then raise my own event indicating that processing is done
        OnSourceFileChanged(new SourceEventArgs(e.Name));
    }
}

Basically, I want to write an NUnit test that will do the following:

  1. Create a directory
  2. Setup a DirectoryProcessor
  3. Write some files to the directory (via File.WriteAllText())
  4. Check that DirectoryProcessor.SourceFileChanged has fired once for each file added in step 3.

I tried doing this and adding Thread.Sleep() after step 3, but it's hard to get the timeout correct. It correctly processes the first file I write to the directory, but not the second (and that's with the timeout set to 60s). Even if I could get it working this way, it seems like a terrible way to write the test.

Does anyone have a good solution to this problem?


Solution

  • If you are looking to test another object that uses this class my answer is not relevant.

    When I write unit tests to operations I prefer using the ManualResetEvent

    The unit test will be something like:

         ...
         DirectoryProcessor.SourceFileChanged+=onChanged;
         manualResetEvent.Reset();
         File.WriteAllText();
         var actual = manualResetEvent.WaitOne(MaxTimeout);
         ...
    

    when manualResetEvent is the ManualResetEvent and the MaxTimeout is some TimeSpan (my advice always use the time out). now we are missing the "onChanged":

         private void onChanged(object sender, SourceEventArgs e)
         {
              manualResetEvent.Set();
         }    
    

    I hope this is helpful