Search code examples
c#inversion-of-controlstreamreaderstreamwriter

IOC / Injecting StreamReader, StreamWriter Dependencies


I'm looking to learn how to correctly inject dependencies that come from the .NET Core library like StreamReader and FileStream. How do I inject these?

I have a class that reads in a file with a bunch of demographic census data, selects a random sampling of it, and then returns it as multiline string to its caller. It news up a FileStream to get access to a file's contents and then news up a StreamReader to read in the FileStream contents so I can manipulate the text. However, I'm looking to make this unit testable. If I needed to inject a class I created myself I'd generate an interface for the class to implement and pass that into the constructor, but this is a .NET Core type and there's no IFileStream, IStreamWriter, etc that I can inject. What would be the correct way to inject these so I can substitute in mocks during unit testing?

namespace MyNS.Lib
 {
using System.IO;
using System.Text;
using PgpCore;

/// <summary>
/// A class for PGP encrypting strings.
/// </summary>
public class EncryptUtility
{
    /// <summary>
    /// Initializes a new instance of the <see cref="EncryptUtility"/> class.
    /// </summary>
    /// <param name="sampler">The CensusSampler needed by the class.</param>
    public EncryptUtility(CensusSampler sampler)
    {
        Sampler = sampler;
    }

    /// <summary>
    /// Encrypts a census file.
    /// </summary>
    /// <param name="censusFilePath">The path to the census file.</param>
    /// <param name="keyPath">The path to the public key file.</param>
    /// <returns>Returns an encrypted census file.</returns>
    public string EncryptCensus(string censusFilePath, string keyPath)
    {
        using (FileStream census = new FileStream(censusFilePath, FileMode.Open))
        {
            var censusSr = new StreamReader(census);
            var censusText = censusSr.ReadToEnd();
            return EncryptString(censusText, keyPath);
        }
    }
}
}

Solution

  • I think what @devNull said probably makes the most sense. By encapsulating the portions of code that rely on things that don't make sense to inject and mock, I have kind of already separated out the parts of my code that need testing from parts that rely on the .NET Core runtime. I don't really need to test EncryptCensus because the only thing I'd be testing is that StreamReader works, which seems unnecessary. So I'll just test EncryptString. Thanks!