Files as Embedded Resources in Unit Tests

One of the most common unit test mistakes that I see is using relative file paths to actual files. The problem with this is that tests run automatically as part of a build might not have the same file structure that your relative paths assume. A better solution is to use the DeploymentItem attribute in your tests to ensure the necessary resources are copied to the relevant unit test directory, but I prefer a different solution: compiling the files as embedded resources.

A file is added to the project as an embedded resource simply by changing its Build Action in Properties. Once it’s an embedded resource, it can be accessed from your unit tests like this:

private string GetFileContents(string sampleFile)
{
    var asm = Assembly.GetExecutingAssembly();
    var resource = string.Format("MyProject.Tests.SampleFiles.{0}", sampleFile);
    using (var stream = asm.GetManifestResourceStream(resource))
    {
        if (stream != null)
        {
            var reader = new StreamReader(stream);
            return reader.ReadToEnd();
        }
    }
    return string.Empty;
}

Note that the resource name is the Solution Explorer path to the file. So the above example is from a test project named “MyProject.Tests” in a folder named “SampleFiles.” This function accepts a file name and will return the contents of the specified file from that directory as a string.

This technique can be used in conjunction with mocks to simulate a multitude of scenarios like reading a file, retrieving data from a web service, or querying a database.

Here’s a quick example that demonstrates how this could be used to simulate retrieval of data from a web service:

public interface IDataAccess
{
	string GetXmlDataFromWebService();
}

public class MyClass
{
	private readonly IDataAccess _dataAccess;
	
	public MyClass(IDataAccess dataAccess)
	{
		_dataAccess = dataAccess;
	}
	
	public void Execute()
	{
		var xml = _dataAccess.GetXmlDataFromWebService();
		// do more...
	}
}

[TestMethod]
public void Execute_ProcessesXml()
{
	// Arrange
	var mockDataAccess = MockRepository.GenerateMock<IDataAccess>();
	var target = new MyClass(mockDataAccess);
	
	var xml = GetFileContents("TestData.xml");
	mockDataAccess.Expect(x => x.GetXmlDataFromWebService())
		.Return(xml);
	
	// Act
	target.Execute();
	
	// Assert
	mockDataAccess.VerifyAllExpectations();
	// more assertions...
}
Advertisement
%d bloggers like this: