开发者

fake directories for .net unit testing

开发者 https://www.devze.com 2023-02-27 01:22 出处:网络
I\'m trying to create a unit test for a code similar to this: foreach (string domainName in Directory.GetDirectories(server.Path))

I'm trying to create a unit test for a code similar to this:

foreach (string domainName in Directory.GetDirectories(server.Path))
{
     HandleDomainDirectory(session, server, domainName);
}

The problem is that I'm using the System.IO.Directory class in my code. How can I create a testing method that won't be dependent on any folder I have on my hard disk. In other words, How can I fake the response of "Direc开发者_如何学JAVAtory.GetDirectories(server.Path)"? (Please note, I do control the "server" object in my class, therefore i can give any path i want)

Thanks.


Rather than calling Directory.GetDirectories(server.Path) directly, you could create an interface like IDirectoryResolver with a single method that takes a path string and returns the list of directories. The class containing your code above would then need a property or field of type IDirectoryResolver, which can be injected through the constructor or a setter.

For your production code, you would then create a new class that implements the IDirectoryResolver interface. This class could use the Directory.GetDirectories method in its implementation of the interface method.

For unit testing, you could create a MockDirectoryResolver class which implements IDirectoryResolver (or use a mocking library to create a mock instance for the interface). The mock implementation can do whatever you need it to do.


You would inject a wrapper class.

public class DirectoryFetcher
{
     public virtual List<string> GetDirectoriesIn(string directory)
     {
          return Directory.GetDirectories(directory);
     }
}

And then inject that:

foreach(string directory in _directoryFetcher.GetDirectoriesIn(server.Path))
{
    // Whatever
}

You can then Mock that guy at the injection point (this example uses Moq, and constructor injection):

Mock<DirectoryFetcher> mockFetcher = new Mock<DirectoryFetcher>();

mockFetcher.Setup(x => x.GetDirectoriesIn("SomeDirectory")).Returns(new List<string>
{
    "SampleDirectory1",
    "SampleDirectory2"
});

MyObjectToTest testObj = new MyObjectToTest(mockFetcher.Object);

// Do Test


When communicating with the outside world, such as file system, databases, web services etc. , you should always consider using wrapper classes like the others before me suggested. Testability is one major argument, but an even bigger one is: The out side world changes, and you have no control over it. Folders move, user rights changes, new disk drives appears and old ones are removed. You only want to care about stuff like that in one place. Hence, the wrapper -- let's call it DirectoryResolver like Andy White suggested ealier.

So, wrap your file system calls, extract an interface, and inject that interface where you need to communicate with the file system.


The best solution I've found was to use Moles. The code is very specific, and must do very specific thing. Wrapping it with wrapper class will be redundant. The only reason I needed wrapper class is in order to write tests. Moles allows me to write the tests without any wrapper class :)

0

精彩评论

暂无评论...
验证码 换一张
取 消