Tuesday, October 19, 2010

Invalid code coverage item error in MSTest

I ran into the following running unit tests after a build under TFS 2010:

Invalid code coverage item: The pdb file name must contain at least one character.

I had modified the .testsettings file to use relative paths instead of absolute paths, but the build was failing with the above error.

The solution was to edit the .testsettings file to add a pdbFile attribute:

<CodeCoverageItem binaryFile="..\Utilities\%outdir%\Utilities.dll" pdbFile="..\Utilities\%outdir%\Utilities.pdb" instrumentInPlace="true" />

Continuous integration

This is what I like to run for continuous integration builds:
  1. Set version numbers in all assemblies.
  2. The release build.
  3. Code analysis (build breaker).
  4. Unit tests (build breaker).
  5. Integration tests (build stability).
  6. FitNesse tests (build stability).

Outputs I like to collect are:
  • Build outputs, including PDBs, ideally in a symbol server.
  • Code coverage percentage and details.
  • Test results.

Wednesday, October 13, 2010

Setting up code analysis in Visual Studio

Code Analysis Rule Files

Copy these files to an appropriate location in the source tree:
For test code:
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="Test Code" Description="Rules for unit and integration test assemblies." ToolsVersion="11.0">
  <IncludeAll Action="Error" />
  <Rules AnalyzerId="Microsoft.Analyzers.ManagedCodeAnalysis" RuleNamespace="Microsoft.Rules.Managed">
    <Rule Id="CA1004" Action="None" />
    <Rule Id="CA1014" Action="None" />
    <Rule Id="CA1020" Action="None" />
    <Rule Id="CA1024" Action="None" />
    <Rule Id="CA1026" Action="None" />
    <Rule Id="CA1031" Action="None" />
    <Rule Id="CA1062" Action="None" />
    <Rule Id="CA1300" Action="None" />
    <Rule Id="CA1303" Action="None" />
    <Rule Id="CA1502" Action="None" />
    <Rule Id="CA1506" Action="None" />
    <Rule Id="CA1702" Action="None" />
    <Rule Id="CA1707" Action="None" />
    <Rule Id="CA1709" Action="None" />
    <Rule Id="CA1822" Action="None" />
    <Rule Id="CA2204" Action="None" />
    <Rule Id="CA2210" Action="None" />
  </Rules>
</RuleSet>
For production code:
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="Production Code" Description="Rules for production code." ToolsVersion="11.0">
  <IncludeAll Action="Error" />
  <Rules AnalyzerId="Microsoft.Analyzers.ManagedCodeAnalysis" RuleNamespace="Microsoft.Rules.Managed">
    <Rule Id="CA1004" Action="None" />
    <Rule Id="CA1020" Action="None" />
    <Rule Id="CA1024" Action="None" />
    <Rule Id="CA1026" Action="None" />
    <Rule Id="CA1303" Action="None" />
    <Rule Id="CA1502" Action="None" />
    <Rule Id="CA1506" Action="None" />
    <Rule Id="CA1822" Action="None" />
    <Rule Id="CA2204" Action="None" />
    <Rule Id="CA2210" Action="None" />
  </Rules>
</RuleSet>

Language

I am not aware of a GUI that allows setting the language for Visual Studio code analysis.

To do this manually, add the following line to your .csproj files under the main <PropertyGroup> tag:

<CodeAnalysisCulture>en-NZ</CodeAnalysisCulture>

This setting is obviously for New Zealand English. Consult this table for the appropriate locale ID.

Custom Dictionary

Set up a custom dictionary file called CustomDictionary.xml and add a link to it in one of your projects. Set the build action (in the properties page) to CodeAnalysisDictionary. To duplicate this into other projects in the same solution, just drag into each of those solutions. I use the following as a default:
<Dictionary>
  <Words>
    <Unrecognized>
      <Word></Word>
    </Unrecognized>
    <Recognized>
      <Word>Mvc</Word>
      <Word>Serialise</Word>
      <Word>Serialisation</Word>
      <Word>Serialiser</Word>
      <Word>Deserialise</Word>
      <Word>Deserialised</Word>
      <Word>Deserialisation</Word>
      <Word>Nesse</Word>  <!--From FitNesse-->
    </Recognized>
    <Deprecated>
      <Term PreferredAlternate=""></Term>
    </Deprecated>
    <Compound>
      <Term CompoundAlternate=""></Term>
    </Compound>
    <DiscreteExceptions>
      <Term></Term>
    </DiscreteExceptions>
  </Words>
  <Acronyms>
  </Acronyms>
</Dictionary>

Project Configuration

In each project's property pages under the Code Analysis tab, set the rule set to either the test or production set, and enable the code analysis for release builds only. Running code analysis slows down the build and may not be suitable for debug builds.

TFS

In your continuous integration build definition, set code analysis to Always.

Friday, September 10, 2010

Flattening an AD group hierarchy

Sometimes it can be difficult to find all the members of an active directory group when there are multiple child or sub groups.

To flatten the hierarchy, use this command:
dsquery group -limit 0 | select-string group_to_find | dsget group -members -expand

Friday, August 6, 2010

Calculating prices after GST changes

There has been some dodgy maths in the New Zealand media recently around how much things will cost after the GST increases in October. The rate will be increasing from 12.5% to 15%, so some media are simply adding 2.5% on top of the price. Unfortunately, the calculation is not that simple. First, you need to remove the current GST portion, and then calculate the new price with the new GST rate:



Unfortunately, the calculation is not easy to do in your head: 46 × originalprice / 45. Another way of looking at it is to add 1/45 of the current price, or ~2.22%

Friday, July 16, 2010

Overriding protected members using Moq and/or RhinoMocks

Sometimes I want to override a protected method on an internal class using a mocking framework and make verifications against calls to that method. This problem also occurs when trying to mock an internal interface in the assembly under test.

When doing this with Moq or RhinoMocks (both of which use the same proxy generator), I got the following error:

"Castle.DynamicProxy.Generators.GeneratorException: Type is not public, so a proxy cannot be generated."

The solution is to publish the internals of the assembly under test to the appropriate assembly:

[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2," +
    "PublicKey=00240000048000009400000006020000002400005" +
    "25341310004000001000100c547cac37abd99c8db225ef2f6c8" +
    "a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7" +
    "852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0" +
    "a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15" +
    "605093924cceaf74c4861eff62abf69b9291ed0a340e113be11" +
    "e6a7d3113e92484cf7045cc7")]

Tuesday, July 13, 2010

Relative paths in .testsettings file

To configure relative code coverage paths in the .testsettings file, you will need to manually edit the xml file. First configure your coverage DLLs using the UI, then open the .testsettings file in a text editor, or in VS using the VS text editor.

Edit the absolute paths to be relative to the location of your testsettings file, and use the %outdir% macro instead of bin\Debug:
..\..\Utilities\%outdir%\Utilities.dll