How to refer to test files from Xunit tests in Visual Studio? - visual-studio-2013

We’re using Xunit for testing. We’re running our tests via the built-in Visual Studio 2013 Test Runner, using the Xunit plugin.
The issue is that some of the tests need to refer to files on the filesystem. It seems that Xunit (or the VS Test Runner—not sure which), copies the assembles, but not any supporting files in the bin directory, to another directory before executing the tests, hence our test files are not found. [The MS Testing framework specifies attributes for listing files to be copied, but Xunit does not.]
How to either disable this copying behaviour, or else programmatically determine the original bin/ directory location to fetch the files?
It seems that most proposed solutions (including on the Xunit bug-tracker site) suggest storing the files as embedded resources instead of ‘copy always’ files. However, this is not always practical, for example: testing file manipulation code, and (in one case) code which wants a Sqlite database file.

Okay, typical, just as soon as I post the question, I find the answer myself…
The gist is that the copying (Shadow Copying) of assemblies seems to be done by the .NET framework, not by Visual Studio or by Xunit.
We had been using Assembly.Location to locate the assembly file, and hence the test files. However, this was wrong, since it gave us the location of the Shadow-Copied assembles instead of the originals.
Instead you should use Assembly.CodeBase to fetch the base assembly code location. However, this is a (File) URL, so it’s necessary to extract the path from the URL. The new (C#) code looks like this:
var codeBaseUrl = new Uri(Assembly.GetExecutingAssembly().CodeBase);
var codeBasePath = Uri.UnescapeDataString(codeBaseUrl.AbsolutePath);
var dirPath = Path.GetDirectoryName(codeBasePath);
return Path.Combine(dirPath, relativePath);
…where relativePath is the path relative to the Bin\ directory.

After a bit of search I found the solution here: https://msdn.microsoft.com/en-us/library/ms182475.aspx.
Particularly, the first step has been enough for me:
If they are specific to one test project, include them as content files in the Visual Studio test project. Select them in Solution Explorer and set the Copy to Output property to Copy if Newer.
associated to the following code:
var filename = "./Resources/fake.pdf"
File.OpenRead(filename)

As of .NET5 (perhaps earlier), CodeBase no longer works, so the solution is now to copy all of your files to the bin directory first and use this as your known location.
What makes this OK now, which was always a total pain in the past, is that you can copy a directory to your bin folder easily from your csproj file.
<ItemGroup>
<None
Include="TestFiles\**"
CopyToOutputDirectory="PreserveNewest"
LinkBase="TestFiles\" />
</ItemGroup>
Where TestFiles is in the root of your project folder. Now you can access these files with the following helper method.
public static class TestUtils
{
public static string GetTestPath(string relativePath)
{
var codeBaseUrl = new Uri(Assembly.GetExecutingAssembly().Location);
var codeBasePath = Uri.UnescapeDataString(codeBaseUrl.AbsolutePath);
var dirPath = Path.GetDirectoryName(codeBasePath);
return Path.Combine(dirPath, "TestFiles", relativePath);
}
}

I am running .Net Core 1.0 on Mac. Assembly.GetExecutingAssembly is unavailable. I use the following code instead:
var location = typeof(YourClassName).GetTypeInfo().Assembly.Location;
var dirPath = Path.GetDirectoryName(location);
return Path.Combine(dirPath, relativePath);
relativePath is the path relative to the directory of your DLL.

After struggling with trying to identify directories and copy files (there seem to be multiple directories in play and it's hard to pin down the right one), I found that you can just turn off shadow copying; at that point the unit tests reference content in the bin/{configuration} folder again.
To do so, follow the directions here. It seems to be as simple as setting shadowCopy to false:
{
"shadowCopy": false
}
I'm unclear whether this setting has any adverse interactions with other settings (e.g. appDomain). If anyone knows, your comments would be welcome.

Related

Possibility to relate to other project file in comments?

Is it possible to relate/link to other project files within the comments of the source code (C# in this case) in Visual Studio?
I've found you can use file:// hyperlinks, but those need an absolute path (plus they won't open in the code editor)... there's also <see cref>, which works with R#, but that relates to a symbol that must be referenced by the current project, so that doesn't work in my case.
For my specific case, I'd like to somehow relate Entity Framework's entity POCOs to their mapping configuration class (which resides in other project file which is not referenced by the project where the POCOs are defined).
Absolute paths won't work since this project is being worked on several computers with different absolute paths.
There's also HyperAddin but doesn't seem to have been updated since VS 2008, I'm using 2015.
Any ideas, or add-ins you might have used?
You can automate it with Visual Commander. The simplest command (C#) that requires you to select the relative configuration class file path in the editor (like Project1\config.xml) before calling it:
EnvDTE.TextSelection ts = DTE.ActiveDocument.Selection as EnvDTE.TextSelection;
string relativePath = ts.Text;
string absolutePath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(DTE.Solution.FileName), relativePath);
DTE.ItemOperations.OpenFile(absolutePath, null);

Using project files in NUnit tests

My program deals with input and output files and therefore need to have an access to a folder (included in Visual Studio Project) with existing files, and also create new files and check what's inside.
Tests run on several machines, so absolute path is not an option. Also, I can not self-generate input files.
How I can tell in an NUnit test that I need a folder which is located inside project source tree? NUnit seems to place exe code in some obscure temp folder.
Edit: NUnit 3 is used
Presuming this question refers to NUnit 3, sounds like you need to use TestContext.CurrentContext.TestDirectory.
This gets the directory the assembly was built to, rather that the temp location where it is ran. (Which Environment.CurrentDirectory would return.) Documented here. I believe CurrentContext can also sometimes be null, we use TestContext.CurrentContext?.TestDirectory.
For NUnit 2.X - I believe tests run where they are build, so Environement.CurrentDirectory should be sufficient.

Cross-project references between two projects

Is it possible to make a reference between two TypeScript projects? Assume we have the following project structure:
Module1.ts contains:
module TestModule {
export interface Interface1 {
}
}
Module2.ts contains:
module TestModule {
export interface Interface2 extends Interface1 {
}
}
Test1 is referenced in Test2. I get an error Could not find symbol 'Interface1' in Module2.ts. It works within one project, but I don't know how to make it visible from the other project... Maybe it's not possible for now.
[Edit 1.]
When I try to use TestModule.Interface1 pattern, I get the same error (said in different way). But the IntelliSense sees my Interface1:
[Edit 2.]
I have noticed I can't use files from the other project. Even if I have a correct reference (/// <reference ...) added and linked all the files in my 1st project.
There's lots of ways you can do this.
Option 1 - Project References (TypeScript 3.0+)
If you are using TypeScript 3.0 then look at using project references. Read more here.
Option 2 - Build script
Use something like gulp-typescript, grunt-ts, or just a batch script to copy the files over into a folder in the main project.
Alternatively, run a build event in Visual Studio that will copy the files over to the main project.
Option 3 - npm package
If you use npm, you could create a package for your other project. Then you can use your package in your main project. Specifying a local dependency is a good way to do this or by using something like sinopia, which is a private repository server. I've never used it, but it looks like it would work well.
Option 4 - NuGet package
You could look into creating a nuget package and then installing it locally.
Option 5 - --declaration --outDir compiler option
You can set the --outDir compiler option or the outDir property in tsconfig.json with the directory to your other project then also compile it with --declaration so that it generates the declaration files (.d.ts) too. For example: --declaration --outDir ../Test1/External.
Original Answer (Using --out)
You can do something similar in Visual Studio if you right click on your library project and click properties. In the TypeScript Build tab, check off the option to Combine JavaScript output into file and specify the location in your main project you want it to go (Ex. $(SolutionDir)/TypedApp/External/TypedLibrary.js). Then also check off Generate declaration files in order to generate a .d.ts file.
Once this is done, build your library project and then include the .js, and .d.ts in your main project. Include the .js file in your html and reference the .d.ts in your typescript files.
Each time you rebuild the library project, it will automatically update the main project with the changes.
The solution suggested by #dhsto works but I have found an alternative using linked folders. I have written about it in detail in this article, here is how it can be implemented:
It can be achieved by creating a folder to hold your references, I like to name this “_referencesTS”, the folder will contain all of the links to files from Test1. This can be done individually but would become very cumbersome if it had to be done for each new TS file. Linking a folder however will link all of the files beneath it, this can be done by editing the csproj file.
To edit the file right click the Test2 project and click “Unload Project”, then right click the project and click “Edit Test2.csproj”. Navigate to the <ItemGroup> that contains the <TypeScriptCompile> tags and insert the code below:
<TypeScriptCompile Include="..\Test1\**\*.ts">
<Link>_referencesTS\%(RecursiveDir)%(FileName)</Link>
</TypeScriptCompile>
Replace the relative path to the location of your TS files in Test1, this uses the wildcarding (*) to link all .ts files (dictated by the *.ts) within all sub folders (dictated by the \**\)..
The TS files within these folders will now appear linked within Test2, allowing for automatic typescript referencing.
Note: The only downside to this approach is that when a new file is added to Test1 within a linked folder, the user has to unload and load the project or close and open the solution for it to appear in Test2.
Frustrated with the state of affairs, I wrote a NuGet package that mostly solves this problem. Using the NuGet package you can just add a reference from one project to another and it will do the work of copying files around in a way that is safe from accidentally editing the wrong file and still gives intellisense and debugging.
Details can be found in the Readme.md, or you can just install the NuGet package and run (I recommend at least reading the how to use section).
https://github.com/Zoltu/BuildTools.TypeScript.FromReferences
I just want to add to the answer of David Sherret that the lib files to the TypedApp project could be added as Link files instead of depending on post build events. I'm having some issues with post build events in big solutions with a lot of projects, and the link files are now working ok for me. (I cannot add a comment to the answer because I only have 35 reputation points).
If you are compiling with the --out parameter you can simply reference Module1.ts from Module2.ts using /// <reference To learn more about code organization patterns in TypeScript see http://www.youtube.com/watch?v=KDrWLMUY0R0&hd=1
What visual studio language services sees available (which is everything) is different from what you compile and actually have available at runtime.
If you need to share the code between multiple projects you can always create a symbolic link on each project where you need it.
http://en.wikipedia.org/wiki/Symbolic_link
basarat's answer is the closest to being the most reliable solution for cross-project TypeScript references. However, when merging shared TypeScript code with a referencing project's TypeScript (important, for example, if you need to target different ECMAScript versions), the Source Map file doesn't resolve to the shared project's directories, so debugging won't work (in fact, Visual Studio often crashes after adding breakpoints to the files referenced in another project).
Linked files of any kind (Visual Studio links and symbolic links) don't work with debugging in any system (Visual Studio, Chrome, WebStorm, etc.)--linked files essentially don't exist to the ASP.NET debugger, nor any other debugger; they exist only in Visual Studio.
Please see this question/answer indicating what has worked great for both solid code maintenance and debugging in Visual Studio, Chrome, and Firefox, while still retaining the ability to combine shared code with the referencing projects' code (important, for example, if you need to target different ECMAScript versions): Visual Studio: How to debug TypeScript in a shared project using IIS Express and cross-project references (no linking or duplicating files)
The accepted answer disallows debugging in Visual Studio when a breakpoint is set in the Shared project. (At best the debugger will stop on a line in the compiled javascript, but not the original Typescript and certainly not in its original project location.)
In the Shared project's properties, let's say that Combine Javascript output into [a single] file is checked and set to AllShared.js, which also makes a AllShared.d.ts file because Generate declaration files is checked, and also makes a AllShared.js.map because Generate source maps is checked.
The referencing project should NOT copy or link these files in the way the accepted solution does. Instead:
Part 1, in the referencing project, create /typings/tsd.d.ts if it doesn't already exist, and append to the bottom of that file the line ///<reference path="../../SharedProject/AllShared.d.ts" />. Once this is done, (and at least one successful compile of SharedProject is done), Intellisense and the Typescript compiler should see Interface1 etc. (You'll likely get a red squiggly line underlining the statement if the path/file doesn't exist, which is nice.)
Part 2, in the referencing project's index.html, add the line <script src="http://localhost:29944/AllShared.js"></script> before that project's own script tags. The localhost part comes from the Shared project's Properties, Web tab, Project Url. (Both 'IIS Express' and 'Local IIS' work.)
Now when you run the referencing project, you should see Internet Explorer** request the relevant files from their respective "websites". Visual Studio breakpoints should be hit regardless whether they're in SharedProject or the referencing project.
. Although this solution works without gulp/grunt/powershell, Visual Studio's Combine Javascript output into one file doesn't glue together the files in any particular order, and it will eventually break your code. Then you'll need to add Gulp/etc. to the referencing project to insert a <script src="http://localhost:29944... tag for each file in Shared***, because keeping index.html updated by hand is a poor option. (Adding Gulp to the Shared project, to concat the .js and .d.ts files into singles runs into an issue with .js.map files, which can't be simply concatted.)
** IE and VS are both Microsoft products, so IE really works better if you want to use VS's breakpoints and debugger instead of a web browser's.
*** Gulp doesn't like injecting urls, only filepaths. Given HTML comments in index.html like <!-- SharedStuff:js --><!-- endinject -->, circumvent this like so:
gulp.task('insert-into-html', [], function () {
var common = gulp.src(['../SharedProject/**/*.js'], { read: false });
return gulp.src('./index.html')
.pipe(inject(common, {
relative: true,
name: "SharedStuff",
transform: function (filepath) {
return '<script src="http://localhost:29944/'+filepath+'"></script>';
}
}))
.pipe(gulp.dest('./'));
});

How do I create a Visual Studio project template that includes linked files?

In Visual Studio 2010, I want to create a project template that includes links to two files that should exist on the system. One of them is a common AssemblyInfo.cs file. Another is the strong name key file (*.snk).
I need these references to be relative, because each developer's workspace will be set up differently. Is it possible for the project template to somehow figure out where these files reside in each developer's environment?
From reading about templates, it sound like they're pretty static so I wonder if tricks can be done to do something like this. If nothing else, I can add bogus references that will cause compilation errors and force the developer to hook these files in. But if I can do it for them, that would be better.
You should set the CreateInPlace property to true in the vstemplate. The documentation says
Specifies whether to create the project and perform parameter replacement in the specified location, or perform parameter replacement in a temporary location and then save the project to the specified location.
If you want relative paths to work, you need the parameter replacement to occur in the place where you're creating the project, not in a temporary location.
Microsoft have confirmed that this is a bug with the extensibility model and project templates. I managed to get round this by using IWizard. I added the following code in the RunFinished method of my IWizard implementation:
//Get linked file directory
string coreDir = Path.GetDirectoryName(MyProject.FullName);
//Data folder
ProjectItem propertiesProjectItem = slSharedProject.ProjectItems.Cast<ProjectItem>().Where(p => p.Name == "Data").First();
propertiesProjectItem.ProjectItems.AddFromFile(coreDir + #"\Service\TheFileIWantToLink.cs");
This code links in a copy of TheFileIWantToLink.cs file to my shared Silverlight project (slSharedProject).
You could try to integrate a Wizard into your Project Template and set the Paths to the linked files. If i remember right you don't have to create an User Inteface; you only have to specify the correct replacements in the replacementsDictionary and VS will replace the values in your Template File. See this or this for further information.

How to get MSTest to find my test data files?

I have a few tests that need to be fed with external data from excel files. The files are included in the test project, and in Visual Studio, I have edited the test settings file (Local.testsettings) to deploy the data files. This makes it work fine i VS.
We are, however, also running continous integration with TeamCity, and in TeamCity this doesn't work. My data files are unavailable to the test. Seems that the tests are run from a temporary folder named "C:\TeamCity\buildAgent\temp\buildTmp\ciuser_AS40VS6 2009-12-11 09_40_17\Out", and the data files are not copied there.
I have tried changing the build action for the data files to "Resource" and setting copy to output dir to "Always", but that didn't help.
Does anyone know how to make this work?
I am running Visual Studio 2010 beta 2 and TeamCity 4.5.5, which is why I'm running MSTest in the first place, and not NUnit...
I get round this by adding my data files (in my case usually XML) as embedded resources and I extract them from the test assembly.
[TestInitialize]
public void InitializeTests()
{
var asm = Assembly.GetExecutingAssembly();
this.doc = new XmlDocument();
this.doc.Load(asm.GetManifestResourceStream("TestAssembly.File.xml"));
}
This post answers this question: MSTest copy file to test run folder
The accepted answer is technically correct. However, from my experience, I find that the embedding files as resources requires an additional step of remembering to set the property "Embedded Resource". This becomes a challenge when you have a large number of data files. Also, with increasing number of data files, the size of the unit test assembly keeps growing . In my case, I had over 500MB of test data files and packing all them into the assembly was not a good idea.
What is the alternative?
Let the data files remain as they are. Do not use DeploymentItemAttribute, do not use embedded resources. Please refer my proposed solution How do I make a data file available to unit tests?

Resources