Ugly Stool Rotating Header Image

Tests with External File Dependencies

Testing a system where you have to reach outside the environment can be awkward.  A piece of code that requires a file name instead of a Stream is bad, and to be avoided.  While this can be enforced when using one’s own code, it is not true when utilizing third party code.

If you have to test an interaction with file data there are several ways to handle it.

  1. Explicitly copy the file in the test.
  2. Use the test framework to ensure the file is deployed with your test.
  3. Embed the test data in your assembly, and recover the file data at test time.

I favor option the last option because I think it offers the most flexibility.  The first option requires you to account for a resource beyond your test and binary bits.  The second option requires you to manage data outside of your IDE, i.e. cleaning up all of those test specific directories.

Step 1: Add the file to test against to the solution.  I typically add mine to an examples folder in the test project.

image

Step 2: Embedded the file in the assembly, so when you build the project the file is packed into the assembly.

To embed the file on build do the following.

  1. Right-click the file to embed.
  2. Select properties.
  3. Under Build Action select Embedded Resource.

image

Step 3: Create an extension method to extract the resource data to a temporary location on disk.

public static class MyExtensions
    {
        public static string LoadFileAssemblyResource(this Assembly assembly, string resourceName)
        {
            string tempFileName = Path.GetTempFileName();
            using (FileStream fileStream = File.OpenWrite(tempFileName))
            using (Stream stream = assembly.GetManifestResourceStream(resourceName))
            {
                stream.CopyTo(fileStream);
            }
            return tempFileName;
        }
    }

I like the idea of an extension method, but it is not required.  Accepting the Assembly as a parameter is necessary because you will probably need to differentiate between assemblies instead of just picking the executing assembly.

Step 4: Write a test that requires the external file, run the test, assert the results, and cleanup the fie.

[Fact]
public void Test()
{
    string fileName = Assembly.GetExecutingAssembly().LoadFileAssemblyResource(
        "My.Tests.examples.example1.txt");
    try
    {
        var lines = File.ReadAllLines(fileName);
        Assert.Equal(5, lines.Count());
    }
    finally
    {
        File.Delete(fileName);
    }
}

NOTE: The name of the file is not used to locate the file in the assembly, rather the name of the resource is.  The resource name is made up of the default assembly namespace, the folder path, and the name of the file all concatenated by a period.  This is why the file is loaded by using the name “My.Tests.examples.example1.txt” and not “example1.txt”.

Comments are closed.

Page optimized by WP Minify WordPress Plugin