Debugging a R# unit test runner

Debugging a R# test runner is, thankfully, not an experience most people will have to go through.

Because ReSharper runs unit tests in a separate process, spun up on demand, you need to find some way to attach to this process.

The brute force approach is simply to throw an exception somewhere in your plugin, and then attach.

A better alternative is to launch VS in ReSharper.Internal mode (or “god mode”, as some like to refer to it) by supplying the /ReSharper.Internal argument to devenv.exe. (You can also enable a specific plugin by using /ReSharper.Plugin “MyPlugin.dll”, which spares some of the pain when trying to build a plugin that is in use).

This provides you with some extra options. The one you want is “Enable Debug (Internal)” which can be found in ReSharper->Options->Tools->Unit Testing:

Once this is enabled, when you run a test a dialog will appear:

Giving you time to attach to the test runner:

External Annotations for ReSharper

Most ReSharper information comes from code inspection and analysis, but not all details can be inferred from the source code alone. For example, code called by reflection (e.g. Activator.CreateInstance) looks like dead code to static analysis. R# offers a solution in the form of External Annotations, XML files supplying extra information.

If you use a test framework other than NUnit, e.g. MbUnit, you may find that your tests are marked as unused by R# even though they can be run. This can fixed by supplying some annotations, the XML needs to go in “%SystemDrive%\Program Files\JetBrains\ReSharper\[Build#]\Bin\ExternalAnnotations\[DllName]\[DllName].xml”. So for MbUnit, it would be ExternalAnnotations\MbUnit\MbUnit.xml. The file needs a list of types, associated with the appropriate R# attribute. The MeansImplicitUseAttribute:

<assembly name="MbUnit">
  <member name="T:MbUnit.Framework.TestAttribute">
    <attribute ctor="M:JetBrains.Annotations.MeansImplicitUseAttribute.#ctor" />
  </member>

states that any code tagged with the TestAttribute will not be considered unused. Other useful attributes are the AssertionMethodAttribute:

  <member name="M:MbUnit.Framework.Assert.IsNotNull(System.Object)">
    <attribute ctor="M:JetBrains.Annotations.AssertionMethodAttribute.#ctor"/>
    <parameter name="anObject">
      <attribute ctor="M:JetBrains.Annotations.AssertionConditionAttribute.#ctor(JetBrains.Annotations.AssertionConditionType)">
        <argument>3</argument>
      </attribute>
    </parameter>
  </member>

the TerminatesProgramAttribute:

  <member name="M:MbUnit.Framework.Assert.Fail">
    <attribute ctor="M:JetBrains.Annotations.TerminatesProgramAttribute.#ctor"/>
  </member>

and the NotNullAttribute. An external annotation file is shipped with the more recent versions of MbUnit.