0

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?

Vinay
  • 469
  • 3
  • 14

2 Answers2

2

Typically, you are concerned with testing the interaction with the file system and there is no need to test the framework classes and methods that actually perform the operations.

If you introduce a layer of abstraction into your classes, you can then mock the file system in your unit tests to verify that the interactions are correct without actually manipulating the file system.

Outside of testing, the "real" implementation calls into those framework methods to get the work done.

Yes, in theory you'll need to integration test that "real" implementation, but it should in practice be low-risk, not subject to much change, and verifiable through a few minutes of manual testing. If you use an open source file system wrapper, it may include those tests for your peace of mind.

See How do you mock out the file system in C# for unit testing?

Community
  • 1
  • 1
Jay
  • 56,361
  • 10
  • 99
  • 123
0

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

Eyal H
  • 991
  • 5
  • 22
  • Thanks! I wasn't familiar with the ManualResetClass! On balance, I think that filesystem mocking is the correct way to go for unit tests. I do also like writing these more integration-y tests that let me see how the code works. – Vinay Aug 30 '12 at 21:16