Wednesday, December 22, 2010

Enabling Code Coverage in VS2010 without MSTest

Just so I don’t forget how to do it…

The command-line sequence is as follows:

  1. Instrument the assemblies that you want to provide code coverage information using VSInstr.exe (32-bit version at %VSInstallDir%\Team Tools\Performance Tools\VSInstr.exe, or 64-bit version at %VSInstallDir%\Team Tools\Performance Tools\x64\VSInstr.exe) with the /COVERAGE switch.
    This will write two new files for the instrumented assembly (if PDB’s are available) named after the instrumented assembly and its PDB file with the pdb.instr extension.  The original assembly is renamed to AssemblyName.Extension.orig and the original PDB is left unchanged.

    A side effect of this instrumentation is that your assembly will now have a dependency on VSCoverX.dll (where X is 80, 90, or 100, depending on the Visual Studio version).  This dependency is what sends your coverage information to the performance profiler.
  2. Start the performance profiler using VSPerfCmd.exe (32-bit version at %VSInstallDir%\Team Tools\Performance Tools\VSPerfCmd.exe, or 64-bit version at %VSInstallDir%\Team Tools\Performance Tools\x64\VSPerfCmd.exe) so that it can begin collecting code coverage information.  The command-line is /START:COVERAGE /WAITSTART /USER:”%USERDOMAIN%\%USERNAME%” /TARGETCLR:vn.n.nnnn /OUTPUT:”pathToCodeCoverageResultFile.
  3. Perform your tests (using the same bit-ness that you’re profiling, 32-bit or 64-bit), either manually or using whatever automated testing framework you wish.
  4. Stop the performance profiler using VSPerfCmd.exe with the /SHUTDOWN switch.
  5. As a last step, rename your *.orig assemblies back to their original names, either deleting or renaming the instrumented versions.

You should now be able to open the code coverage file at pathToCodeCoverageResult in Visual Studio to examine the code coverage information, or create an XML report using VSPerfReport.exe.

Technorati Tags: ,,

Thursday, December 09, 2010

Wednesday, December 01, 2010

Delegate Identities

Technorati Tags: ,

Verified some interesting behavior today that I had suspected but wasn’t entirely sure of.  It appears that a System.Delegate’s identity is determined by the object instance (or type) and method that it points to, and that the Combine and Remove methods (called when you add or remove an event handler) perform some kind of reference counting to determine how many times equivalent delegates should be invoked.

A simple example of this behavior can be demonstrated by creating two EventHandler delegates pointing to the same handler method.  Add one of those delegates to the event, but remove the other…the handler will never be called when the event is raised since both delegates are equivalent.  However, if you add the same delegate multiple times to the event, then the handler will be called as many times as the delegate was added, and you must remove the delegate (or an equivalent delegate) at least the same number of times in order for the handler not to be called.

Here’s the Console app used to verify this behavior.

using System;
using System.ComponentModel;

internal class
Program
{
private static readonly object myEventKey = new object();

private readonly EventHandlerList eventHandlers = new EventHandlerList();

private event EventHandler MyEvent
{
add
{
eventHandlers.AddHandler(myEventKey, value);
}
remove
{
eventHandlers.RemoveHandler(myEventKey, value);
}
}

private static void Main(string[] args)
{
Program program = new Program();

Console.WriteLine("Adding two delegates with distinct identities pointing to the same method.");

EventHandler myEventHandler1 = MyEventHandler;
EventHandler myEventHandler2 = MyEventHandler;

program.MyEvent += myEventHandler1;
program.MyEvent += myEventHandler2;

Console.WriteLine("Raising MyEvent (expecting MyEvent to be called twice).");

program.OnMyEvent(EventArgs.Empty);

Console.WriteLine("Removing a new delegate pointing to the previously added methods.");

EventHandler myEventHandler3 = MyEventHandler;

program.MyEvent -= myEventHandler3;

Console.WriteLine("Raising MyEvent (expecting MyEvent to be called twice, once for myEventHandler1 and once for myEventHandler2).");

program.OnMyEvent(EventArgs.Empty);

Console.WriteLine("Removing myEventHandler1 from the event handler list.");

program.MyEvent -= myEventHandler1;

Console.WriteLine("Raising MyEvent (expecting MyEvent to be called once, for myEventHandler2.");

program.OnMyEvent(EventArgs.Empty);

Console.WriteLine("Creating a specific delegate that will be used in both add and remove.");

EventHandler myEventHandler = MySpecificEventHandler;

Console.WriteLine("Adding specific delegate to the handler list.");

program.MyEvent += myEventHandler;

Console.WriteLine("Raising MyEvent, (expecting MyEvent to be called twice, once for myEventHandler2 and once for myEventHandler.");

program.OnMyEvent(EventArgs.Empty);

Console.WriteLine("Removing specific delegate from the handler list.");

program.MyEvent -= myEventHandler;

Console.WriteLine("Raising MyEvent, (expecting MyEvent to be called once, for myEventHandler2 that has never been removed.");

program.OnMyEvent(EventArgs.Empty);

Console.WriteLine("Press the 'Enter' key to stop the server.");

Console.ReadLine();
}

private static void MyEventHandler(object sender, EventArgs e)
{
Console.WriteLine("MyEventHandler Called.");
}

private static void MySpecificEventHandler(object sender, EventArgs e)
{
Console.WriteLine("MySpecificEventHandler Called.");
}

private void OnMyEvent(EventArgs e)
{
EventHandler myEvent = (EventHandler)eventHandlers[myEventKey];
if (myEvent != null)
{
myEvent(this, e);
}
}
}




…and this is the output of the test above:


DelegateIdentityBehaviorTest


Cool.  I became sure of something today that previously I had only thought I knew.