DeploymentItem – A tale of the unexpected…

Do you know how to separate the knowing from the naive, the pros from the amateurs and the men from boys? It’s just by their reaction in certain situations. It’s the cold shivering and slight cough they get if you just whisper a single word, a word like “DeploymentItem”.

So what causes these reactions? Mortals would call it an attribute in MS Test. The most demonic one I have to add. If used, it defines external resources which shall be provided during a test run. Following test case shows the basic idea behind it. You say: “Deploy the file.” and Visual Studio deploys it for you, at least it should…

[TestMethod]
[DeploymentItem("bar.txt")]
public void MyTestMethod()
{
   Assert.IsTrue(File.Exists("bar.txt"));
}

The snippet for example only works if “bar.txt” is part of your test project and is deployed to the output folder. If it isn’t there you might have a problem and not even seeing it because Visual Studio will not show any errors in the test output, at least no visible errors. This just doesn’t happen for example if you’ve forgotten to set the Build Action to None and the Copy to Output Directory to Copy always. Another common mistake is to not check the „Enable Deployment“ checkbox in your test settings, which is absolutely not obvious but will bring the whole deployment thing to a halt.

If you use NUnit, this might sound a bit strange because you might would expect that the file already exists if it is part of your project. MS Test runs all it tests inside an own folder and deploys only files to this folder which are referenced by the project so if you have a file you also need (because of late binding and IoC for example) you have to configure it.

That doesn’t sound quite dangerous but it is because VS remembers every file it has deployed and will not do it again during a test run!

[TestMethod]
[DeploymentItem("bar.txt")]
public void TestMethod1()
{
   Assert.IsTrue(File.Exists("bar.txt"));
   File.Delete("bar.txt");
}

[TestMethod]
[DeploymentItem("bar.txt")]
public void TestMethod2()
{
   Assert.IsTrue(File.Exists("bar.txt"));
   File.Delete("bar.txt");
}

This example might look strange but it shows a common misunderstanding. Just because you attached the attribute to both methods does not say, that the file is deployed separably for both. It is deployed once and that’s why one of the tests will fail. You can also not say which of them will fail because you never can be sure in which order they are executed. For example, the MS Test Test runner seems to have another execution order than the test runner of Resharper. Even worse Resharper copies the files into another directory than MS Test and can cause a lot of confusing when it comes to run test on a build machine (with MS Test) which ran perfectly on the developer machine.

You see that the DeplyomentItem can cause dependencies between your tests you usually wouldn’t have. This isn’t a problem as long as you don’t change the data of the file but it can be quite annoying and confusing if you use it without knowing of this special „feature“…

[TestMethod]
[DeploymentItem("bar.txt", @"Test1")]
public void TestMethod1()
{
   Assert.IsTrue(File.Exists(@"Test1\bar.txt"));
   File.Delete(@"Test1\bar.txt");
}

[TestMethod]
[DeploymentItem("bar.txt", @"Test2")]
public void TestMethod2()
{
   Assert.IsTrue(File.Exists(@"Test2\bar.txt"));
   File.Delete(@"Test2\bar.txt");
}

A workaround for situations where you need to change the file or its content, is to deploy each file of each test into an own folder. Now you can delete them as often you want without any problems.

Kommentar hinterlassen