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... }
Awesome post. Just ran into this ‘issue’ today and this blog helped me a lot! Thanks!
Great example, was helpful!
This will work only text files, right?
No, this works with any file type. My GetFileContents method returns a string, but you could easily modify it to return a byte array.
Just stumbled across this with a generic google search on embedded resources in unit tests. I remember now, you’re the one that taught me how to do it in the first place 8 years ago! Thanks for the lesson – and the re-lesson ;-).
Ha! So funny. Well, if the internet is going to think I’m an expert on anything, I’m glad it’s embedded resources in unit tests 🙂
Thanks for taking time to drop a note–I hope you’re doing well! (Well-wishing adjusted for 2020)
Thanks for your sweet article (-: