DeploymentItem 属性的问题

我目前正在维护一个用 C # .net 编写的“旧”系统,删除一些过时的特性并进行一些重构。感谢上帝,前面的人写了一些单元测试(MSTest)。我对 JUnit 测试非常满意,但是对 MST 测试还没有做太多。

测试方法有一个 DeploymentItem属性,指定一个文本文件,该文件由正在测试的业务逻辑方法进行解析,还有一个 DeploymentItem,其中只指定了一个路径,其中包含一组必须部署的 TIF 文件。

[TestMethod()]
[DeploymentItem(@"files\valid\valid_entries.txt")]
[DeploymentItem(@"files\tif\")]
public void ExistsTifTest()
{
...
}

以前的测试可以工作,但是现在我必须更改包含在 TIF 文件目录中的 TIF 文件的名称。根据规则,TIF 文件名必须匹配某种模式,这也由 ExistsTifTest()方法检查。 现在我不得不更改文件名,以使它们适应新的需求,突然之间,TIF 文件不再像以前那样被部署。

谁能给我一个提示,为什么会发生这种情况,或者原因是什么?如果我在文件的有效目录中添加一个新的文本文件“ my2ndTest.txt”,并在测试方法中使用相应的 DeploymentItem 属性,也会发生同样的事情。文件没有被部署吗?

我现在通过直接在 testrunconfig 中定义部署路径来部署映像,但是我想知道为什么会发生这些事情,或者为什么我的新文件“ my2ndTest.txt”没有得到部署而其他文件得到了部署。

86075 次浏览

DeploymentItem is a bit of a mess.

Each file in your solution will have a "Copy To Output Folder" setting in VS.NET. You need this to be "Copy Always" (or similar) in order to get the files into the output folder.

Check that you've got this set for the new files. If you don't have this set then the files won't get copied to the output folder, and then they can't be deployed from the output folder to the folder where MSTest does it stuff.

Personally, if I have files that I need for my unit tests I've found that embedding those files as resources into an assembly, and having that assembly "unpack" itself during the tests is a more predictable way of doing things. YMMV.

note: These comments are based upon my experience with VS2010. Comments to my answer would suggest that this is not problem with VS2012. I still stand by comments that using embedded resources involves less "magic" and, for me, makes the "arrange" stage of my unit tests much more explicit.

If you go into your .testrunconfig file and under deployment uncheck "Enable Deployment", the tests will run in their normal location, and everything will work like it does when running the app outside a unit test.

In VS2010, my Local.testsettings had the "Enable Deployment" unchecked and the DeploymentItem attribute was not working. I checked it and everything worked fine. I hope this helps!

Since I always found the DeploymentItem attribute a mess, I do the deployment of such files by using the post-build script. - Make sure the files you wanna copy has the Copy Always property set. - Modify your test project post-build script to copy the files from build target folder(Bin\Debug) to the location where your test is expecting them.

This probably doesn't relate to your exact problem, but here's a couple of tips I found with the [DeploymentItem] attribute.

  1. Copy to output directory should be set to Copy Always.

It does NOT work when used with the [TestInitialize] attribute

[TestInitialize]
[DeploymentItem("test.xlsx")]
public void Setup()
{

It should be on your [TestMethod], e.g.

    [TestInitialize]
public void Setup()
{
string spreadsheet = Path.GetFullPath("test.xlsx");
Assert.IsTrue(File.Exists(spreadsheet));
...
}


[TestMethod]
[DeploymentItem("test.xlsx")]
public void ExcelQuestionParser_Reads_XmlElements()
{
...
}

I had Deployment flag disabled first. But even after I enabled it, for some unknown reason nothing even target DLLs would still be copied. Accidentally I opened Test Run window and killed all the previous runs and magically I found all the DLLs and files I needed in the test folder the very next run... Very confusing.

Try this for VS2010. So you do not need to add DeployItems for every tif
Remove the

[DeploymentItem(@"files\valid\valid_entries.txt")]
[DeploymentItem(@"files\tif\")]

Add a test configuration.
- right-click on solution node in solution explorer
- Add -> New Item...
- Select Test Settings node on the left, select the item on the right
- Click Add

Call it eg TDD

Choose TDD under TestMenu > Edit Testsettings.

Click on the Deployment. Enable it and then Add the files and directories that you want.There will be a path relative to the solution. The files will be put on. The original file are for example here:

D:\Users\Patrik\Documents\Visual Studio 2010\Projects\DCArrDate\WebMVCDCArrDate\Trunk\WebMVCDCArrDate\Authority.xml

When I run my unit test it gets copied to

D:\Users\Patrik\Documents\Visual Studio 2010\Projects\DCArrDate\WebMVCDCArrDate\Trunk\WebMVCDCArrDate.Tests\bin\Debug\TestResults\Patrik_HERKULES 2011-12-17 18_03_27\Authority.xml

in testcode I call it from:

[TestMethod()]
public void Read_AuthorityFiles_And_ParseXML_To_Make_Dictonary()
{
string authorityFile = "Authority.xml";
var Xmldoc = XDocument.Load(authorityFile);

There is no need to choose Copy Always; put the files in the testproject; add hardcoded paths in the testcode. For me this solution worked best. I tried with DeploymentItem, copy always but it was not to my liking.

For hopefully helping someone else out: I tried all the suggestions here and still my deployment item was not being copied.

What I had to do (as suggested here) was to add a second parameter to the DeploymentItem attribute:

[DeploymentItem(@"UnitTestData\TestData.xml", "UnitTestData")]

Not sure if this exactly answers the question, but it may help some. First, I've found the "Enable Deployment" box must be checked for deployment to work. Second, the doc says the source path is "relative to the project path" which at first I took to mean the project folder. In fact, it seems to refer to the build output folder. So if I have a project folder called 'TestFiles' and a file in it called Testdata.xml, using the attribute this way doesn't work:

[DeploymentItem(@"TestFiles\Testdata.xml")]

I can mark the Testdata.xml file Copy Always, so that the build puts a copy under the output folder (e.g., Debug\TestFiles\TestData.xml). The deployment mechanism will then find the copy of the file located at that path (TestFiles\Testdata.xml) relative to the build output. Or, I can set the attribute this way:

[DeploymentItem(@"..\\..\TestFiles\Testdata.xml")]

and the deployment mechanism will find the original file. So either works, but I have noticed that using the Copy Always I occasionally run into the same problem I have when editing the app.config file in a project - if I don't change code or force a rebuild, nothing triggers copying of files marked to be copied on build.

After trying all of the other suggestions listed here I still couldn't figure out what was going on. Finally I discovered that there was no settings file selected under Test/Test Settings menu, which meant that Deployment wasn't being enabled. I clicked the Test/Test Settings/Select Test Settings File menu item, selected the Local.TestSettings file, then everything worked.

I was having huge problems trying to get files to deploy - trying all the suggestions above.

Then I closed VS2010; restarted it, loaded the solution and everything worked. (!)

I did some checking; After setting the 'Enable deployment' flag on local.TestSetting you should not simply re-run the test from the Test Results window. You have to get the previous test run removed from the UI e.g. by running a different test, or by re-opening your solution.

I have also faced similar problems but i found easy 3 step solution for this:

Assuming your folder structure looks like this: SolutionFolder\ TestProjectFolder\ SubFolder\

  1. Go to "Solutions Items/Local.testsettings" > "Deployment" > Check "Enable Deployment"
  2. If you are using VS2010, make sure any files you want to deploy have their "Copy To Output Folder" property set to "Copy Always" or "Copy if Newer"
  3. Attribute your TestMethod with either one of:
    • [DeploymentItem(@"TestProjectFolder\SubFolder")] to deploy all contents of <SubFolder> to the Test Run directory
    • [DeploymentItem(@"TestProjectFolder\SubFolder", "TargetFolder")] to deploy all contents of <SubFolder> to <TargetFolder> in the Test Run directory

One final note about MSTest (at least for VS2010):

If you want the <TargetFolder> to have the same name as the <SubFolder>, using [DeploymentItem(@"SubFolder", @"SubFolder")] will fail silently as the MSTest runner hits a silly edge case. This is why you should prefix the <SubFolder> with the <TestProjectFolder> as so: [DeploymentItem(@"TestProjectFolder\SubFolder", @"SubFolder")]

My big "gotcha" was the way DeploymentItem handles directories. I was using the two-parameter version with both as directory path containing subdirectories I wanted deployed. I didn't realize initially that it only copies the stuff in the ROOT of the directory and not the entire recursive folder structure!

I basically had [DeploymentItem(@"Foo\", @"Foo\")] and was expecting it to deploy my Foo\Bar. I specifically had to change it to [DeploymentItem(@"Foo\Bar\", @"Foo\Bar\")] and now it works like a charm.

I've been working on this in VS2013. My findings to get this working:

  • Copy to output directory should be set to Copy if Newer / Copy Always: MANDATORY.
  • "Enable Deployment" in .TestSettings: NOT REQUIRED. I got this working without a .TestSettings file at all.
  • Specifying a folder as 2nd parameter: OPTIONAL. Shapes the output folder layout, works fine without.
  • SPACES in the filename: this caused me a headache - the file was never copied. Removing the spaces fixed this. Haven't looked into escape characters yet.

A tip I also learned the hard way: do not forget to add this attribute to each individual test. The file copies on the first attributed test in the testrun, but remained missing when the order of the tests changed and non-attributed tests tried to find the file first.

I have also faced similar problems. I have all the steps mentioned above but still no luck. I am using VS2010. Then i have found that $Menu > Test > Select Active Test Setting > Trace and Test impact was selected. It started working after i change Trace and test impact to Local. This page contains very resourceful information about copying files to test results folder, I feel to add this experience as well.

For those who prefer to avoid the mess of DeploymentItem and take the approach suggested by @Martin Peck (accepted answer), you can use the following code to access the contents of the embedded resource:

public string GetEmbeddedResource(string fullyQulifiedResourceName)
{
var assembly = Assembly.GetExecutingAssembly();
// NOTE resourceName is of the format "Namespace.Class.File.extension";


using (Stream stream = assembly.GetManifestResourceStream(fullyQulifiedResourceName))
using (StreamReader reader = new StreamReader(stream))
{
string result = reader.ReadToEnd();
}
}

For details, see this SO Thread

For me, the root cause was something else entirely: The production code being exercised by my tests was renaming and/or deleting the .xml test file being deployed.

Therefore, when I would run my tests individually, they'd pass, but when running them all together, the 2nd and subsequent test would fail with "file not found" errors (which I'd originally misdiagnosed as the DeploymentItem attribute not working).

My solution was to have each individual test method make a copy of the deployed file (using this technique), and then have the production code being tested use the copied file instead of the original.

We have spent a lot of time by Deployment items problem to solve it in local unittest run and teamcity unittest reun as well. It is not easy.

Very good tool to debug this issue is ProcessExplorer. Using process explorer, you can check where is Visual Studio searching for the deployment items and make the correction to the project. Just filter all file operation where path contains your deploymentitem filename and you will see it.

Besides the Deployment attribute needing to be checked, I discovered something else about the DeploymentItem attribute.

[TestMethod()]
[DeploymentItem("folder\subfolder\deploymentFile.txt")]
public void TestMethod1()
{
...
}

Your deploymentFile.txt needs to be relative to the solution file and not the testfile.cs.

enter image description here

Don't use DeploymentItem.

It is very hard to set up correctly and it was not working with my ReSharper test runner nor the native one for MSTEST in Visual Studio 2017.

Instead, right click your data file, and select properties. Select Copy to output directory: Always.

Now in your test, do this. The directory is simply the directory of the file relative to the test project. Easy.

    [TestMethod()]
public void ParseProductsTest()
{
// Arrange
var file = @"Features\ParseProducts\Files\ParseProducts_Workbook_2017.xlsx";
var fileStream = File.Open(file, FileMode.Open);
// etc.
}

This does seem to work well with automated build and test systems.

Here is a picture of where the files go in the solution:

enter image description here