NCrunch struggles with
absolute file references, because they usually cause code to break the isolation of the sandbox (workspaces) NCrunch constructs to build your code and execute your tests.
In this particular case, the usage of an absolute path in an environment variable is causing NCrunch to use the same build output path as that used for your foreground solution. This creates two problems:
- Because the assemblies are being built to the same place as your foreground code, you'll get file locking issues. NCrunch uses the assemblies built from your projects in order to execute code. This requires launching and executing task runner EXEs which will hold file locks on any code files they make use of (as any CLR application does). When you try to run a build in Visual Studio, VS attempts to place the newly built assemblies over the top of the assemblies that NCrunch has locked.
- Because the assemblies from multiple projects are all being put in the same place, NCrunch will be unable to exert reliable control over which assemblies are loaded into a test environment. The CLR uses heavily implicit logic for loading assembly references. By forcing all references into the same place, NCrunch cannot intercept the assembly resolution process and you'll get weird issues around the versions of code inside assemblies used by the test process. You'll also get multiple warnings from the NCrunch engine about unexpected assembly resolution. This specific problem can be resolved by turning on the
Preload Assembly References project-level configuration setting.
The solution to this issue is to avoid using absolute file path references. If this isn't compatible with your normal foreground build process, you can
introduce an override into the project file to provide NCrunch with a relative OutputPath, while non-NCrunch builds still use the environment variable. For example:
<OutputPath Condition="'$(NCrunch)' == '1'">bin\</OutputPath>
<OutputPath Condition="'$(NCrunch)' != '1'">$(OUTDIRECTORY)</OutputPath>
You are correct in your understanding that it is very common for people to want to place all assemblies in the same place when a solution is built. In my experience, this is usually done using paths relative to the solution, for example:
<OutputPath>$(SolutionDir)bin\</OutputPath>
NCrunch can automatically handle file paths relative to the solution, as it accounts for the solution directory when padding out the workspace for each project.