C# Unit Test using FileStream

141 views Asked by At

I had a service that would return an image's data URLs, and I want to do unit test for it.

The following is part of its: ("path" parameter is a real path route)

...
using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))
{
    byte[] buffer = new byte[fileStream.Length];
    int bytesRead = fileStream.Read(buffer, 0, buffer.Length);

    if (bytesRead < buffer.Length)
    {
        return ...
    }   
    ...
    return ......
}      

So my question is, how can I mock FileStream without a real path? I used xUnit and Substitute and found that FileStream can use Substitute but not know why it needs a real path for the parameter. How else can I try? Is there any way except to use wrapper?

Thanks for any advice.

1

There are 1 answers

6
Mustafa Özçetin On

The solution is generalizing the method parameter by accepting a Stream object. I assume your current method signature is something like

public byte[] GetImageData(string path)

Change your method to:

public byte[] GetImageData(Stream stream)
{
    byte[] buffer = new byte[stream.Length];
    int bytesRead = stream.Read(buffer, 0, buffer.Length);
    // return your data.
}

In this way, you shift the responsibility of getting the FileStream to the clients and pass in a FileStream instead. Now you are in a more liberal situation when passing the parameter: In actual code you can pass in a real FileStream:

var fileStream = new FileStream("path/to/file", FileMode.Open, FileAccess.Read);
byte[] data = parser.GetImageData(fileStream);

or you can freely create a MemoryStream according to your needs in your test code:

Stream stream = new MemoryStream();
// Manipulate your stream object as you like.
byte[] data = parser.GetImageData(stream);

This is actually an example of programming to interfaces, not concrete implementations and dependency injection. One bonus with this approach is that you will not incur the performance penalty of disk IO in your unit tests.