Deployment Item attribute for unit tests with MSTest
A lot of people seemed to be complaining about this attribute's weird behavior on Stack Overflow. Almost all the answers will suggest trying to change the "Copy to Output Directory" property to "Copy always". To do that, right click on the file and choose properties, then change it from "Do not copy" to "Copy always" or "Copy if newer".
The properties menu looks like this:

That might solve your issue, but it wasn't so simple for me. I was missing a few key pieces of knowledge about how the attribute works. I still don't fully understand it, but I'll try to explain what I figured out and how I got my unit test to pass.
First of all, you're using the DeploymentItem
attribute because your code gets a file from the file system. You're trying to write a unit test, but MSTest deploys the test in a different location, so it can't use your code to find the file you've pointed to. For example, you use a path name like "/project/assets/file.png"
, but MSTest can't use this filepath. The tests are located in the unit test project. So, we have the DeploymentItem
attribute that can take care of this dependency (the file) for us.
The first big thing I got stuck on, is that DeploymentItem
doesn't do anything with the file you're using the attribute for. I thought it would somehow take my original file, copy it for me, and use it. But, it does not do this. You have to actually copy the file yourself and paste it into your unit test project. The attribute finds and uses the file you've copied.
I put my copy into MyUnitTestProject\Content\Images. My attribute looks like this:

The second argument of "Images" was required for me. Without it, the test broke.
Also, on this copied file that you've moved to the unit test project, is where you'll want to right-click, view "Properties", and make sure "Copy to Output Directory" is set to "Copy always" or "Copy if newer".
The second big thing that tripped me up is the way the filename is read in your code. For example, you might pass in a filepath to something as an argument. Something like this:
var filepath = "\\assets\\images\\file.png";
ImageProcessor.ProcessImage(filepath);
But, I've found that this code will not work with the DeploymentItem
attribute. I believe it requires the filename to be isolated. It needs to be a stand-alone string in its own variable. The following code would work:
var myFile = "file.png";
var rootPath = "\\assets\\images";
var fullFilepath = rootPath + "\\" + myFile;
ImageProcessor.ProcessImage(fullFilepath);
Note how the string file.png
is separate. I assume this is necessary for MSTest to swap out one file for the other. I still find it confusing, and was unable to find any info about this strangeness in the documentation or Stack Overflow. But maybe what worked for me can help some of you out there.