Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

NCRUNCH code coverage markers are all white after changing output path of project under test
bibsoconner
#1 Posted : Thursday, February 27, 2014 8:56:39 PM(UTC)
Rank: Newbie

Groups: Registered
Joined: 2/27/2014(UTC)
Posts: 7
Location: United States of America

Recently, I changed the output path of my project (a class library) from the default (../bin/debug) to:

$(OURDIRECTORY_BUILD)\Debug\ where OURDIRECTORY is an environmental (System) variable).

I also changed the UnitTest project (that was in the same solution) to reference the class library like this:

Reference Include="MyLibrary"> $(OURDIRECTORY )\Debug\MyLibrary.dll

Previously, I had just referenced it as a project reference. I made the change from project reference to the above as I was having build problems once I changed the Output Path.

Anyhow, now all is building and the unit tests are all passing BUT when I look at the NCrunch metrics, they are all at 0.00% AND the code coverage markers are all white (no coverage). Obviously, I do have coverage (very close to 100%) and something about changing the output path has confused NCRUNCH. How should I be handling this?

I am somewhat constrained to use this idea of a environmental variable for the output path as my boss is suggesting it. We have multiple libraries being built (not all in same solution) and are trying to make everything build-able on multiple machines. This scheme lets each engineer pick his own path for the environmental variable and even have a couple of code bases that he can switch between by changing the environment variable value.

Let me know if I can provide more details or if there is a more appropriate place to post.

Thanks,

Dave
Remco
#2 Posted : Thursday, February 27, 2014 11:03:49 PM(UTC)
Rank: NCrunch Developer

Groups: Administrators
Joined: 4/16/2011(UTC)
Posts: 6,986

Thanks: 931 times
Was thanked: 1257 time(s) in 1170 post(s)
Hi Dave,

This approach cannot be made to work with NCrunch, because it relies on implicit behaviour describing the references between projects.

NCrunch works by shadowing projects individually and separating them from their parent solution. In the workspaces that NCrunch constructs, the project references are manipulated in order to build a test environment in the fastest way possible without needing to perform additional build steps. For this to work, NCrunch needs to be able to recognise references between the projects as making use of the ProjectReference MSBuild declaration. It cannot infer project references using the Reference declaration. Because of this, you'll find that NCrunch is referencing the MyLibrary.dll file that is sitting in your foreground solution, which cannot be correlated with its source project and therefore no code coverage exists.

Sorry, but you'll need to use a more conventional approach that does not involve referencing binary outputs from dependent projects. There's no way I can make this work for you in its current form.


Cheers,

Remco
bibsoconner
#3 Posted : Friday, February 28, 2014 1:15:41 AM(UTC)
Rank: Newbie

Groups: Registered
Joined: 2/27/2014(UTC)
Posts: 7
Location: United States of America

Thank you for the quick reply Remco. I would think this is a common problem. Forget NCrunch and unit tests for a moment. It does not seem unreasonable to want to combine various libraries/dlls that developers are working on in a common directory. One alternative would be putting all projects in a single solution but that can get unwieldy if there are many projects. So telling all engineers that there will be a hard coded directory where all .dll and .libs will go, and where they will be referenced from, seems like a good idea. The Environmental variable is to answer the objection "but I don't want to use the same directory as everyone else". If there are other more "conventional" approaches, please let me know. However, perhaps I can make changes that accommodate NCRUNCH. My piece of the puzzle is a single library that I would like to have Unit Tests for. Could I, for example, simple have the library and Unit Test project in the same solution, let the library build to it's local bin/debug directory and copy it to the other directory as part of a post-build step? The unit tests could then presumably reference the lib project as a project reference.

UPDATE. I went back to having the unittest refer to the class library as a project reference. It seems to work well enough which is strange as it didn't seem to work before. It still has some quirky behavior though. For example,
if you do a "Rebuild All" while NCrunch is enabled, you get the messages:

Warning 1 Unable to delete file "C:\bin\Frame\3.0\Debug\MyLibrary.dll". Access to the path 'C:\bin\Frame\3.0\Debug\MyLibrary.dll' is denied. MyLibrary

Warning 3 Could not copy "obj\Debug\MyLibrary.dll" to "C:\bin\Frame\3.0\Debug\MyLibrary.dll". Beginning retry 1 in 1000ms. The process cannot access the file 'C:\bin\Frame\3.0\Debug\MyLibrary.dll' because it is being used by another process. MyLibrary
and then finally:
Error 14 Unable to copy file "obj\Debug\MyLibrary.dll" to "C:\bin\Frame\3.0\Debug\MyLibrary.dll". The process cannot access the file 'C:\bin\Frame\3.0\Debug\MyLibrary.dll' because it is being used by another process. MyLibrary

Disabling NCrunch and doing a rebuild all and then reenabling NCrunch seems to do the trick. Not a big deal, but I'm not sure why all was well when I just used relative paths.


Remco
#4 Posted : Friday, February 28, 2014 3:51:03 AM(UTC)
Rank: NCrunch Developer

Groups: Administrators
Joined: 4/16/2011(UTC)
Posts: 6,986

Thanks: 931 times
Was thanked: 1257 time(s) in 1170 post(s)
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.
bibsoconner
#5 Posted : Monday, March 3, 2014 5:40:40 PM(UTC)
Rank: Newbie

Groups: Registered
Joined: 2/27/2014(UTC)
Posts: 7
Location: United States of America

Thanks Remco,

Your idea of using two different OutputPaths seems to have solved things for me. I am able to do a rebuild all without disabling NCrunch and my tests are all passing and the code coverage numbers are accurate.

One lingering thing... You have me wondering if we are setting things up correctly as far as paths and environmental variables. If you have any references to how this should be done, please post them. Again, the situation is that the main app is being developed by one guy (my boss), a library is being developed by me, and perhaps another (or more) library is being developed by someone else. It's reasonable that on their respective local machines there are paths for the workspaces and code files like:

C:\Boss\MainApp
C:\User\Dave\Projects\Visual Studio 2013\MathAndPhysicsLibrary
E:\Remco\IBMProjects\GUIWidgets
G:\Contractor\CommonCode

All of these are separate Visual Studio 2013 solutions.
Imagine MainApp is dependedent on MathAndPhysicsLibrary and GUIWidget and both of those (and MainApp?) are dependent on CommonCode. How best to set up the paths? I suppose one could demand that every programmer grabs the projects and puts them on their local computer in a relative path location. I.e. they could all be at the same level regardless of whether they are on the C drive, E drive and regardless of whether or not they are at root or under User\Dave\Projects. Is this your suggestion? It seemed less burdensome to tell every developer, "Grab the code for each solution and put it anywhere you want. There is an environmental variable that defines the output path for each dll and .exe. AND serves as the reference path the exe (and dlls) to find other dlls. Don't mess with this, but you do get to set the environmental variable to whatever you want." Again, this worked great except with NCrunch as discussed. Unfortunately, I'm the main guy using NCrunch so the sympathy I get is limited and the suggestions I get are along the lines of "Don't use NCrunch. What we are doing is with paths / environmental variables is not that unreasonable.".

Thanks again,

Dave
Remco
#6 Posted : Monday, March 3, 2014 9:17:12 PM(UTC)
Rank: NCrunch Developer

Groups: Administrators
Joined: 4/16/2011(UTC)
Posts: 6,986

Thanks: 931 times
Was thanked: 1257 time(s) in 1170 post(s)
Hi Dave,

Great to hear that did the trick. I'm sorry if I seemed a seemed a little purist earlier while trying to describe NCrunch's limits when handling a situation like this. Although I haven't seen a solution arrangement quite like what you've described, it it an interesting approach and it is not without merit.

I think the best way to look at the structural issue you are trying to solve is to split it into two problems.

The first problem is how to work with team members that store their code in different locations. I have seen many situations where people will simply put down a rule (as you've described) where everyone must have their code in the same place on disk. I agree that this is probably unnecessary and it removes flexibility from the development environment. It also creates an implicit expectation that is not obvious to someone simply pulling down the code to work on it. Generally I try to solve problems such as this one using the source control system. Dependencies between projects and solutions should usually be relative, as this is the best way to decouple a solution from its environment. Most source control systems contain features allowing you to 'check out' dependencies in relative locations to the project being worked on (i.e. SVN externals). Where this is impossible, you might find a structure similar to the one below can often work too:

All Solutions\
All Solutions\Boss\MainApp
All Solutions\IBMProjects\MainApp
All Solutions\Contractor\CommonCode

.. Assuming everyone checks code out of the repository at 'All Solutions', they can easily be kept in sync with the other projects/solutions with minimal effort. Source control updates can be performed against the root of the source tree, so everything stays up to date.

The second problem is dealing with having multiple solutions referencing a selection of projects. I.e. everyone on the team has their own solution, which contains only the projects they work on. Sometimes solutions may contain the same project, and these projects are all interdependent. Usually this means that you end up with a solution containing projects with <ProjectReference> declarations pointing at other projects outside the solution. This is actually a very complex situation that is difficult to find an ideal solution for. Most toolsets don't really handle this very well. NCrunch handles it by automatically resolving referenced projects outside the solution and including them with the engine.

Unfortunately, in order to make the layout work with other tools, people very often strip out the <ProjectReference> tags in the .proj files and replace them with fixed <Reference> tags pointing at the output DLLs of other projects - I guess the same way you have done for at least one of your projects. NCrunch then can't handle this as it doesn't realise you're referencing a project rather than some DLL, so the build doesn't work properly and code coverage is missing. Other (more serious) problems also go in hand with this solution, as MSBuild doesn't recognise the dependency and it may build the projects out of sequence. There's also a much greater risk of the DLL being referenced having been built using different configuration to the depending project (i.e. perhaps it is a DEBUG binary being included in a RELEASE build). Finally, it creates a further dependency on all the code being properly built before being checked into source control, as the DLL version may not be consistent with the source code.

Generally I recommend avoiding using multiple solutions where possible. If your team is working very closely together on different aspects of the same overall problem, they should probably be working in the same solution. If need be, you can set up Solution Folders to split the various projects out, making them easier to manage. Where codebases become unreasonably large to the point where loading all projects slows the IDE to a crawl, often I've found this to be symptomatic of a larger design issue where the solution itself can be broken up in to areas that are worked on less frequently, and can be split up into libraries that don't change often enough to be included with all their source code. Organisational limitations often tend to solve this problem, as large code bases are often split between multiple teams who take responsibility for different parts of the project (and can therefore have their own codebases separate from each other using formal integration points).

There are long term plans to introduce functionality to NCrunch that will solve the composite solution problem entirely. I can't share any details on this right now as it's all still in the planning stage, but it will be exciting when it happens :)

I hope this helps!


Cheers,

Remco
Users browsing this topic
Guest
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

YAF | YAF © 2003-2011, Yet Another Forum.NET
This page was generated in 0.240 seconds.
Trial NCrunch
Take NCrunch for a spin
Do your fingers a favour and supercharge your testing workflow
Free Download