112

I've got a test which requires an XML file to be read in and then parsed. How can I have this file copied into the test run folder each time?

The XML file is set to "Copy if newer" and a compile mode of "none" (since it's not really a compile-able thing)

BIBD
  • 15,107
  • 25
  • 85
  • 137
Aaron Powell
  • 24,927
  • 18
  • 98
  • 150

6 Answers6

135

use a DeploymentItem attribute

using System;
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using CarMaker;

namespace DeploymentTest
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod()]
        [DeploymentItem("testFile1.xml")]
        public void ConstructorTest()
        {
            string file = "testFile1.xml";
            Assert.IsTrue(File.Exists(file), "deployment failed: " + file +
                " did not get deployed");
        }
    }
}
Richard Ev
  • 52,939
  • 59
  • 191
  • 278
Preet Sangha
  • 64,563
  • 18
  • 145
  • 216
  • 17
    The DeploymentItem attribute can also be specified at the class level, to affect every test in the class. – Hannes Nel Aug 12 '11 at 03:45
  • 25
    Don't forget that if you have your items in a subfolder to also include that in the deployment subdirectory [DeploymentItem("SubFolder\testFile1.xml", "SubFolder")] – tom Sep 02 '11 at 12:43
  • @Hannes that is not true, documentation from all versions of VS state this "You can use the DeploymentItem attribute only on test methods, not on test classes." – BlackICE Sep 27 '11 at 16:03
  • 1
    @David I haven't read the documentation about that, but I am using it at the class level, and it is working. Must be unsupported behaviour then, so if it stops working, that will be the first place I'll go looking. Thanks! – Hannes Nel Sep 28 '11 at 22:02
  • 33
    Further to Thomas' comment, The default value for RelativePathRoot is the Solution Folder, so if your solution looks like this (..\SolutionFolder\TestProject\TestData\aFile.txt) Your DeploymentItem would look like this.. ([DeploymentItem(@"TestProject\TestData\aFile.txt", "TestData")]).. and you would reference the file in the test using this..(string file = @"TestData\aFile.txt";) – Michael Dausmann Nov 23 '11 at 00:59
  • 6
    [DeploymentItemAttribute documentation for VS2010](http://msdn.microsoft.com/en-us/library/ms245570.aspx): _This attribute can be specified on a test method or on a test class._ – Alex Che Feb 22 '12 at 16:43
  • Is it possible to get hold of the attribute DeploymentItem's filename so I can refer to it in my method and not have to type the name twice? – Matthew Lock May 04 '12 at 05:28
  • 1
    I think you can use a constant ( const string fName = "blah"; ), as it will need to be compiled in. So you can refer to the constant string in your method – Preet Sangha May 04 '12 at 05:45
  • 1
    I can get it this way, but surely there's a more concise way?! ((DeploymentItemAttribute)(System.Reflection.MethodBase.GetCurrentMethod().GetCustomAttributes(typeof(DeploymentItemAttribute), true)[0])).Path – Matthew Lock May 04 '12 at 05:48
  • True. But that seems a bit over top for just a constant. – Preet Sangha May 04 '12 at 05:59
  • just trying to avoid having it repeated in the code incase one is changed and the other is forgotten ;) – Matthew Lock May 04 '12 at 06:08
  • 2
    but a class level const is just that eh? – Preet Sangha May 04 '12 at 06:08
  • 1
    @MichaelDausmann, what you wrote isn't working for me. I put my file in the root of the solution (right next to the .sln file), and then used [DeploymentItem(@"foo.txt")], yet foo.txt never gets copied. How can I debug DeploymentItem to see where it is looking for the file? – Patrick Szalapski Jul 20 '12 at 20:50
  • 12
    What most posts I have seen that fail to mention is that if you can't get this to work, you probably need to check the "Enable Deployment" checkbox, which you can find if you go to Test -> Edit Test Settings -> local (local.testsettings) -> Deployment tab. I just did this and then DeploymentItem worked fine. – Dave Aug 20 '12 at 20:56
  • This solved running the test using MSTest on TeamCity, but broken tests started directly from VisualStudio. I solved this by adding *.runsettings file using these guides: https://msdn.microsoft.com/en-us/library/ms182475.aspx and https://msdn.microsoft.com/en-us/library/jj635153.aspx – petrsyn Oct 15 '15 at 11:54
  • DeploymentItem(sourceFileNameWithPath, targetDirPath) first argument is the source path relative to the solution folder (see Michael Dausmann"s comment), the second one is a path relative to the test execution Out directory. So 1.) to make sure that the test data file was deployed to your test execution directory, open \TestResults\\Out and make sure the file is there. 2.) to refer to it, use @"targetDirPath\sourceFileName" in your test code. – balintn Aug 19 '18 at 21:34
28

It seems that if you provide a TestSettings file for the Solution then you can uncheck the "Enable deployment" option and stop mstest from trying to run from the ...TestResults\...\out folder where it doesn't copy your extra files (unless you make them a deployment option).

This is also useful if you depend on the extra files being in a preserved folder structure because Deployment items all seem to be copied directly (flat) into the temporary run folder (out) if you use the Deployment, Add Folder option in the TestSettings (answers above suggest you can keep the structure if you add each item as its own DeploymentItem).

For me it worked fine running tests directly in Visual Studio (i.e. my extra files in their structure were found and used by tests) because I had created a TestSettings file for another reason long ago (which has Enable deployment unchecked), but not when TeamCity ran mstest to run tests because I hadn't specified that the TestSettings file should be used.

To create a TestSettings file in Visual Studio, right click on the Solution and choose New Item, and select the TestSettings template. To use the TestSettings file at the command prompt of mstest.exe add the option, /testsettings:C:\Src\mySolution\myProject\local.testsettings (or add as an extra command line option in TeamCity with appropriate path)

TamW
  • 381
  • 4
  • 3
8

The Preet answer is used to deploy items for a single test. If you want to do it at solution level, use the .testrunconfig settings.

Eric Bole-Feysot
  • 13,949
  • 7
  • 47
  • 53
5

Best solution to me is using testsettings, especially if multiple tests need the same datafiles.

First create a testsettings file, and add the deployment items you need (file or folder name):

<TestSettings name="Local" id="00ebe0c6-7b64-49c0-80a5-09796270f111" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
  <Description>These are default test settings for a local test run.</Description>
  <Deployment>
    <DeploymentItem filename="Folder1\TestScripts\test.xml" outputDirectory="TestScripts"/>
    <DeploymentItem filename="Folder2\TestData\" outputDirectory="TestData"/>
  </Deployment>
<...../>
  • Running in visual studio, use "select Test Settings File" from "Test\Test Settings" menu to select new testsettings

  • Running mstest, use the /testsettings parameter to have mstest use your testsettings.

FrankyHollywood
  • 1,497
  • 19
  • 18
2

You can define DeploymentItem in a class that holds a method with AssemblyInitialize attribute. Then you're sure that the files are copied regardless of which test you run.

Unfortunately DeploymentItem attribute is executed only on classes which contain tests you're running. So if you have 10 test classes which use the same set of files, you have to add the attribute to all of them.

Also found out that changes in *.testsettings files are not automatically refreshed in Visual Studio. Therefore after adding files / folders into deployment in testsettings, you have to reopen solution file and then run the tests.

Sielu
  • 1,070
  • 14
  • 19
2

In Visual Studio 2012, vstest.console.exe (the built-in test runner) runs with the output dir as the current path. This means that you only need to include the items in your solution with the 'Copy always' or 'Copy if newer' property for them to be used by your test. You don't need the DeploymentItem attribute for the general case. The same applies when running vstest.console.exe from the command line inside your output/test directory.

There are some cases where a separate folder is used, one of them being when you are using the DeploymentItem attribute. See here for more information.

acarlon
  • 16,764
  • 7
  • 75
  • 94