Let's say we have a short program:
namespace ConsoleTryIt
{
static class Program
{
static void Main(string[] args)
{
var sum = Add(1, 2);
}
private static int Add(int p, int p2)
{
return p + p2;
}
}
}
When create the unit test class for this class, Visual Studio create a test method with the attribute DeploymentItem. I read MSDN about this attribute but still don't get what it means.
/// <summary>
///A test for Add
///</summary>
[TestMethod()]
[DeploymentItem("ConsoleTryIt.exe")]
public void AddTest()
{
var expected = 122;
var actual = Program_Accessor.Add(1, 121);
Assert.AreEqual(expected, actual);
}
If you get the idea, please share!
Edit
Thanks everyone for your answers. So the idea is to copy the item given in the argument to the testing evironment's folder. My next question is: why does this method need this attribute while others don't?
I guess it's related to the private members on the tested class but nothing clear to me.
Please continue to discuss.
This specifies files that are required by the specific test. The test system creates a new directory where the tests are run from. With this attribute, you can make the test system copy specific files to that new directory.
Is used deploy files that are not necessary present in the Output directory to the folder used for that particular TestRun.
in the example you posted above, the test environment makes sure that "consoleTryIt.exe" is copied(and therefore present) in the test folder.
If the file is not found, the test is not even run, and a FileNotFound Exception is returned.
This means that the item is copied to the 'TestResults\Out' folder and is basically an artifact/necessary item for the test run. Thus, it is stored apart from the bin directory and does not get overwritten.
This is especially useful when running the tests in different environments (build server, no hard-coded paths...) and of course it is necessary to make the tests repeatable.
HTH.
Thomas
Ensures the files required for the test are copied over to the folder where MSTest runs its tests TestResults\Out.
Files in your solution should have "Copy Always" set for the files to be first copied to bin folder and then to MSTest's folder.
Make sure you have "Enable deployment" checked in testrunconfig.
Related
I recently encountered an odd issue when performing unit tests. My solution contains a helper class with a property for getting the directory of the executing assembly. It looks like this:
public static class DirectoryHelper
{
public static string ExecutingAssemblyDirectory
{
get
{
var codeBase = Assembly.GetExecutingAssembly().CodeBase;
var uri = new UriBuilder(codeBase);
var path = Uri.UnescapeDataString(uri.Path);
return Path.GetDirectoryName(path);
}
}
}
This method is called through various test classes to get relative file paths to dependent resources.
Take the following contrived projects as examples:
TestProject1.dll - TestFixture1.cs
[TestFixture]
public class TestFixture1
{
[Test]
public void VerifyExecutingAssemblyDirectory1()
{
StringAssert.Contains(#"\TestProject1\bin\Debug",
DirectoryHelper.ExecutingAssemblyDirectory);
}
}
TestProject2.dll - TestFixture2.cs
[TestFixture]
public class TestFixture2
{
[Test]
public void VerifyExecutingAssemblyDirectory1()
{
StringAssert.Contains(#"TestProject2\bin\Debug",
DirectoryHelper.ExecutingAssemblyDirectory);
}
}
When these tests are ran individually they pass and the location of the returned assembly is the debug folder of the test class.
However, when ran together, TestFixture2.VerifyExecutingAssemblyDirectory2() is actually returning the path to the bin folder of TestProject1, rather than TestProject2.
I'm trying to determine why this behavior is happening and understand a better way of going about this.
I've found that using .GetCallingAssembly will resolve this problem, but it doesn't seem like I should have to do this.
I've created an example to reproduce this issue and posted to GitHub. TylerNielsen/NUnitExecutingAssemblyExample
Note: I'm aware of the TestContext.TestDirectory in NUnit, however this library is currently not dependent on NUnit and I'd prefer to keep it that way.
UPDATE
I'm running the NUnit tests through both Resharper in Visual Studio and via NUnit3-Console. When I run using NUnit3-Console, I'm only specifying the two individual .dlls and not providing any other arguments.
Both TestProject1 and TestProject2 reference the assembly containing DirectoryHelper. I'm assuming that your references cause the assembly to be copied to the individual (separate) output directories.
When you run both test assemblies together, one of them causes it's "personal" copy of that assembly to be loaded. The second one finds that the assembly is already in memory.
Of course, this behavior will depend on how you run the assemblies, which you haven't said. In the case where you use nunit3-console, it will also depend on your command-line arguments, especially whether you use a separate process for each assembly.
Does anybody know what this sign means?
You're looking at a Debug Watch or Quick Watch Window similar to this one:
The stop sign is added when the member you're watching is marked as internal. Each access modifier has its own indicator. As you can see from the picture and the code that belongs to it:
static void Main(string[] args)
{
var test = new Test();
// put breakpoint here
}
public class Test : TestBase
{
internal int SomeNumber;
protected int FooNumber;
}
public abstract class TestBase
{
internal int AbstractInternalSomeInt;
public int OtherInt;
private byte SomeByte;
}
Notice that in the class view and in the Solution Explorer the symbol for internal members is different, it shows a heart instead:
I came across this post when searching for "visual studio solution explorer no entry symbol". In my case the symbol was presented when using the file view of solution explorer rather than class view. It turned out this was because my gitignore file had an exclusion to all files "*.userprefs" and I'd added project called "userprefs" - what are the odds!
Easy way to fix - right click the files in solution explorer and choose "Add ignored file to source control". Would be worth checking that this makes the desired change to the .gitignore file
In files view, I think it indicates the file is excluded from the build.
Maybe (as in my case) the file is directly included into something that is part of the build.
Look at properties > Excluded from build
Description
I am writing unit tests for a method, which copies a file from a source to a destination. Basically it includes this code:
public void MyMethod()
{
// ...
File.Copy(source, destination, true);
// ...
}
In my unit test project, I have a test file: (test.png), which is located in the Resources folder of my unit test project. And I've set the Copy to Output property to Always.
I have 3 unit tests which are testing this method.
When they hit the line of the code which copies the file: source = "Resources\\test.png".
Issue
When I run the unit test individually, they all pass and everything is fine.
However, when I run All Tests in Visual Studio, I get this run time error and unit tests fail:
System.IO.DirectoryNotFoundException
Could not find a part of the path 'Resources\test.png'.
My Thoughts...(UPDATED)
Probably because Visual Studio runs each unit tests simultaneously in a separate thread and they all accessing the same file at the same time?
I think for every unit test, Visual Studio is cleaning bin/Debug and bin/Release folders. Then it copies all the required project files in that folder. This causes sometimes the file actually does not exist?
Question
How can I fix this problem?
Is there any settings of configurations to resolve this?
How can I run all unit tests in Visual Studio (and Team City) when multiple unit tests are accessing the same file?
You could try to rule out the multi-threading issue by following the instructions from MSDN: Executing Unit Tests in parallel on a multi-CPU/core machine, setting parallelTestCount to 1. If the tests now pass, you've narrowed down the problem.
However, if your tests are still failing when you run them in a group - and I think this is the more likely scenario -, then my advice would be to check for any state those tests are sharing. The pattern you describe (i.e. passes in isolation; fails when not in isolation) is a symptom typically exhibited by tests that are (incorrectly) sharing state, and that state is being modified by those tests, causing one or more tests to fail.
Accessing the same file should not be a problem. Make sure you don't have a cleanUp Fixture(TestSuite level) to delete the file. Because from exception it looks like the file is being deleted after running a test.
Also concurrent read operation is fine and perfectly legal. If your unit tests are overwriting the file then it's a problem.
What happened was, since I was using relative path to the testing files, for some reason when running the unit tests in batch, test runner working directory is different than when running individual tests, hence it couldn't find the directory.
So I used this function to build the absolute path to the testing files:
private string GetFilePath([CallerFilePath] string path = "")
{
return path;
}
Then:
string projectDir = Path.GetDirectoryName(GetFilePath());
string testFile = Path.Combine(projectDir, #"Resources\test.png";
I'd speculate that your problem is that one of the tested methods changes directory, given the explicit "Directory Not Found" exception. It's improbable that file locking or any concurrency problems would cause the behaviour described.
If unit testing you shouldn't really be testing whether File.Copy (or any of the File class methods) worked since you didn't write that code. Instead you should test whether your code interacts correctly with the File type (i.e. did it pass the correct source file name, desination file name and overwrite value when you called "Copy"). First create an interface for the File class and a wrapper for it that implements the interface;
public interface IFileWrapper
{
void Copy(string sourceFileName,string destFileName,bool overwrite);
//Other required file system methods and properties here...
}
public class FileWrapper : IFileWrapper
{
public void Copy(string sourceFileName, string destFileName, bool overwrite)
{
File.Copy(sourceFileName, destFileName, overwrite);
}
}
You should then make the class you are testing include an IFileWrapper parameter (dependency injection). In your unit tests you can then use a mocking framework such as Moq or you could write your own mock;
public class MockFileWrapper : IFileWrapper
{
public string SoureFileName { get; set; }
public string DestFileName { get; set; }
public bool Overwrite { get; set; }
public void Copy(string sourceFileName, string destFileName, bool overwrite)
{
SoureFileName = sourceFileName;
DestFileName = destFileName;
Overwrite = overwrite;
}
}
In real implementations pass in FileWrapper as the IFileWrapper parameter but in your unit tests pass in MockFileWrapper. By checking the properties of mockFileWrapper in your unit tests you can now determine whether you class calls Copy and how it is called. Since you are no longer sharing a real file between your unit tests you will avoid the chance of the tests sharing state or potentially locking the file.
As you mentioned in your answer, the test framework does not always run tests with the working directory set to your build output folder.
To instruct the test framework to place build artifacts or other files from your build output into the test directory, you need to use DeploymentItemAttribute. For your case, you would do something like:
const string destination = "Destination.txt";
const string source = "MyData.txt";
[DeploymentItem(source)]
[TestMethod]
public void MyMethod()
{
// …
File.Copy(source, destination, true);
// …
}
[TestCleanup]
public void Cleanup()
{
// Clean up the destination so that subsequent tests using
// the same deploy don’t collide.
File.Delete(destination);
}
Also ensure that your files are marked with a Build Action of Contents and Always Copy. Otherwise, they won’t be in the build output directory and won’t be able to be copied to the test directory.
Is it possible to retrieve the path of a SpecFlow feature file during runtime in a Step Definition?
Snippet:
[Given(#"Some given statement")]
public void GivenSomeGivenStatement() {
var featureFilePath = // retrieve the path of the feature file
// that executes this step.
}
Context:
We do testing on databases and queries. The source data is created in Excel files and .SQL files (for check queries). These source data are large datasets, not feasible to put into the feature files itself or use the SpecFlow.Plus.Excel extension.
To keep the data close to the feature file, we want to have this data in the same folder as the feature file itself. To achieve this, we need the path to this feature file, so we also have the path to the testdata.
Here's a suggestion. This is just something I put together quickly so lots of room to improve. It relies on the Feature file name being identical to the title of the feature you provide in the description. It also assumes you have a conventional folder structure for your SpecFlow VS project as there is a lot of string manipulation.
Firstly, the calling code should use the SpecFlow BeforeScenario attribute. Something like this:
public void BeforeScenario()
{
//grabs Feature Title from SpecFlow context
var featureName = FeatureContext.Current.FeatureInfo.Title;
//Calls method to obtain path of file
var featureFilePath = GetFeatureFilePath(featureName);
}
The method GetFeatureFilePath will then look like this:
private static string GetFeatureFilePath(string featureName)
{
string startupPath = Environment.CurrentDirectory;
var splitStartupPath = startupPath.Split(new[] {"\\"}, StringSplitOptions.None);
var featureFolder = splitStartupPath[0] + #"\\" +
splitStartupPath[1] + #"\\" +
splitStartupPath[2] + #"\\" +
splitStartupPath[3] + #"\\" +
splitStartupPath[4] + #"\\" +
splitStartupPath[5] + #"\\Features\";
var dir = new DirectoryInfo(featureFolder);
foreach (var fi in dir.GetFiles())
{
if (fi.FullName.Contains(featureName))
return fi.FullName;
}
return "No Feature File Found With Title: " + featureName;
}
It grabs your current directory and splits it to the point where the Features folder should be. It then iterates through each feature file until it finds one that contains your feature title in its path name and returns that as a full path.
I'm not aware of any other way to get this currently.
I don't think knowing the path to the feature file will be possible, as the feature file is used to generate a file containing the unit tests and this is compiled and copied to the test run directory.
The simplest thing will be to set the files as part of the solution and then have them copied to the output directory when the project builds.
If you are using NUnit as the test framework then the files should be in the same directory as the tests are executing so you should just be able to load them without specifying any path, or using the Assembly.GetExecutingAssembly().Location to findout where the code is actually executing.
If you are using MSTest then you need to add a [DeploymentItem(FileToDeploy)] attribute to the test to ensure that the file actually gets deployed with the tests when they are run. Unfortunately as Specflow generates the tests it won't add this for you. To solve this you need to create a partial class which has the same name as the class which contains the tests. This class is called the same as the feature with 'Feature' tagged on the end. So if you have this in your feature:
Feature: Do A Thing
The your test class will be called DoAThingFeature
so you need to create a partial class like this:
[DeploymentItem("FileToDeploy.ext")]
public partial class DoAThingFeature
{}
to ensure that MsTest copies the file you need to the correct directory.
Edit
based on your comment you could maybe do something similar to this
add tags to your feature #hasFiles #source:myFile.xlsx
Then you could add this class:
[Binding]
public class DeployFiles
{
[BeforeScenario("hasFiles")]
public void CopyFiles()
{
..in here find the current executing directory and search
..the subtree for any files defined in the
..ScenarioInfo.Tags array that start with `source:` and copy
..them to the current executing directory
}
}
then any scenario tagged with the #hasFiles will deploy any files specified by #source tags to the root directory where the tests are running.
Not pretty and I'm not certain it'll work, but it might.
maybe this could help you , in .net 4.5 you can get the hold of the path to the caller, take a look at this thread source path in .net 4.5
The goal is to run some tests given some data in those Xml files.
How would you easily load a given Xml file into an XmlDoc within the unit test methods?
Current state is:
XmlDocument doc = new XmlDocument();
string xmlFile = "4.xml";
string dir = System.IO.Directory.GetCurrentDirectory() + #"\Msgs\"
//dir is then the value of the current exe's path, which is
//d:\sourcecode\myproject\TestResults\myComputer 2009-10-08 16_07_45\Out
//we actually need:
//d:\sourcecode\myproject\Msgs\
doc.Load( dir + fileName); //should really use System.IO.Path.Combine()!
Is it just a simple matter of putting that path in an app.config? I was hoping to avoid that, given the possibility of different paths on developer machines.
Question: How would you write the algorithm to load a given Xml file into an XmlDocument in the unit test method?
There is a Visual Studio Unit Testing feature for this: DeploymentItemAttribute
I use this feature to copy all xml files in a given project folder to the unit test output folder, before testing if all required files are present.
You can use this attribute with your unit tests to copy specific files from the Project folder (or anywhere else) to the Unit Test output folder. Like so:
[TestMethod()]
[DeploymentItem("MyProjectFolder\\SomeDataFolder\\somefile.txt", "SomeOutputSubdirectory")]
public void FindResourcefile_Test()
{
string fileName = "SomeOutputSubdirectory\\somefile.txt";
Assert.IsTrue(System.IO.File.Exists(fileName));
}
You can also copy the contents of whole folders:
[TestMethod()]
[DeploymentItem("MyProjectFolder\\SomeDataFolder\\", "SomeOutputSubdirectory")]
public void FindResourcefile_Test()
{
string fileName = "SomeOutputSubdirectory\\someOtherFile.txt";
Assert.IsTrue(System.IO.File.Exists(fileName));
}
The first parameter is the source, the second the destination folder. The source is relative to your solution folder (so you can access the Unit Test project of the project being tested) and the destination is relative to the output folder of the unit test assembly.
UPDATE:
You need to enable Deployment in the Test Settings for this to work. This MSDN page explains how (it's real easy): http://msdn.microsoft.com/en-us/library/ms182475(v=vs.90).aspx#EnableDisableDeploy
You can build those files into your executable (set their "Build Action" property to "Embedded Resource") and then get them using the Assembly.GetManifestResourceStream method.
In the unit test project add a post-build event that copies the XML file to the output directory. Then, you can use your original code to get the XML file.
The post build event will look like something like this:
copy $(SolutionDir)file.xml $(ProjectDir)$(OutDir)file.xml
You may also need this to add to your path:
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
I use a helper class to deal with getting basic paths I might want to access in my Unit Tests.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Brass9.Testing
{
public static class TestHelper
{
public static string GetBinPath()
{
return System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
}
public static string GetProjectPath()
{
string appRoot = GetBinPath();
var dir = new DirectoryInfo(appRoot).Parent.Parent.Parent;
var name = dir.Name;
return dir.FullName + #"\" + name + #"\";
}
public static string GetTestProjectPath()
{
string appRoot = GetBinPath();
var dir = new DirectoryInfo(appRoot).Parent.Parent;
return dir.FullName + #"\";
}
public static string GetMainProjectPath()
{
string testProjectPath = GetTestProjectPath();
// Just hope it ends in the standard .Tests, lop it off, done.
string path = testProjectPath.Substring(0, testProjectPath.Length - 7) + #"\";
return path;
}
}
}
Sometimes my interactions with paths are more complex; I often use a central class I name "App" to indicate some basic details about the application, like its root folder, its root namespace and module, etc. Classes will sometimes depend on App's existence, and so instead I'll place an init method on App that uses code like the above to initialize itself for test harnesses, and call that method from the Init command in a Unit Test.
(Updated)
Old Answer
I found this helps for getting arbitrary paths to access files in the project folder you intend to test (as opposed to files in the Test project folder, which can make busywork if you need to copy things over).
DirectoryInfo projectDir = new DirectoryInfo(#"..\..\..\ProjectName");
string projectDirPath = projectDir.FullName;
You can then use either of those variables to access whatever you need from the related project. Obviously swap "ProjectName" out for the actual name of your project.
Resources are just resources and that's it, no need to complicate. If you don't want to embed them then you could add these files as "Content" resources to your project and set them to Copy always. Then specify the sub-folder in your code:
var xmlDoc = XElement.Load("ProjectSubFolder\\Resource.xml");
This will automatically load the resources from the project output (running assembly location) bin\$(Configuration)\ResourceSubfolder\
This works for all types of projects, not just unit tests.
I would just put the path in the app.config and load from the default path. In my team, i am really anal about developers changing paths, so i make all my developers have the same exact paths and files on their computers, so i dont have an issue of any rogue developer changing a path to suite his workspace.
For example , all developers in my team must use C:\Project\Product\Module, etc etc. I also make sure all their software installed also is standard. This way, i can ghost any machine into any other easily.
I think in VS.NET 2012 DeploymentItem attribute works without any Test Settings configuration.