Following up from yesterday, about an instrumenting coverage tool that I'd spotted on Googlecode (Apr 2015 : rescued to GitHub), what I needed to do to get the instrumenting coverage tool working under .net 3.5sp1 with nUnit 2.5.2 driving unit tests.
First, the command line looks like
[path to]\ClassLibrary1.dll [path to]\UnitTestClassLibrary1.dll /x coverage.xml /r /exe [tool path to]\nunit-console.exe [path to]\UnitTestClassLibrary1.dll
where the /r (backup and replace) flag is essential; so you need to work on a copy directory with your assemblies and their .pdb files.
Second, you need to make the following change to the coverage main program in Runner.cs, line 92 from
to be
The hard-coded relative path could be added as yet another argument instead; and I've not played around with the shadow-copy parameter.
But that at least -- with a totally trivial test set -- provided me with a clean run and non-empty coverage data.
So the next thing to do will be to port the whole lot to .net 4 and see what gives. Also, it will be worth trying the teamcity branch (faking NCover 1.x) to see whether the different AppDomain usage there means we don't have to resort to this trick.
Later: doing a rebuild of Coverage and the sample test under .net 4, with command line
[path to]\ClassLibrary1.dll [path to]\UnitTestClassLibrary1.dll /x coverage.xml /r /exe [tool path to nunint 2.5.4]\nunit-console.exe /framework=net-4.0.30319 [path to]\UnitTestClassLibrary1.dll
where the nunit-console.exe.config
has been adjusted appropriately, I get
Copyright (C) 2002-2004 James W. Newkirk, Michael C. Two, lexei A. Vorontsov.
Copyright (C) 2000-2002 Philip Craig.
All Rights Reserved.
Runtime Environment -
OS Version: Microsoft Windows NT 6.0.6002 Service Pack 2
CLR Version: 2.0.50727.4200 ( Net 2.0 )
ProcessModel: Default DomainUsage: Multiple
Execution Runtime: net-4.0.30319
Unhandled Exception:
System.NullReferenceException: Object reference not set to an instance of an object.
Server stack trace:
at NUnit.Util.ProcessRunner.Load(TestPackage package)
at NUnit.Core.ProxyTestRunner.Load(TestPackage package)
at NUnit.Util.RemoteTestAgent.AgentRunner.Load(TestPackage package)
at System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr md, Object[] args, Object server, Int32 methodPtr, Boolean fExecuteInContext, Object[]& outArgs)
at System.Runtime.Remoting.Messaging.StackBuilderSink.PrivateProcessMessage(RuntimeMethodHandle md, Object[] args, Object server, Int32 methodPtr, Boolean fExecuteInContext, Object[]& outArgs)
at System.Runtime.Remoting.Messaging.StackBuilderSink.SyncProcessMessage(IMessage msg, Int32 methodPtr, Boolean fExecuteInContext)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at NUnit.Core.TestRunner.Load(TestPackage package)
at NUnit.Core.ProxyTestRunner.Load(TestPackage package)
at NUnit.Util.ProcessRunner.Load(TestPackage package)
at NUnit.ConsoleRunner.ConsoleUi.Execute(ConsoleOptions options)
at NUnit.ConsoleRunner.Runner.Main(String[] args)
However, if I do this as a two-stage operation
[path to]\ClassLibrary1.dll [path to]\UnitTestClassLibrary1.dll /x coverage.xml /r
to instrument the code and create a coverage file with zero visit counts throughout -- and then run nunit separately with rest of the command line
[tool path to nunint 2.5.4]\nunit-console.exe /framework=net-4.0.30319 [path to]\UnitTestClassLibrary1.dll
this then fills in the visit counts as expected.
We have code coverage for .net 4 -- at least under some conditions! And without having to rebuild any tools apart from coverage.exe!
Later yet (refrigerator logic) -- of course when working coverage in two passes, I don't need to do the fiddle to change the settings for the AppDomain
. And I don't need to have coverage built in the same .net version as I want to run nUnit in, either. I can use the code as synched from Googlecode built under .net 3.5 even for .net 4 codebases; all I have to do now is fix the problems with running it over F# code.