RSS Log in
 

Quick instructions on making R# 6.0, StyleCop 4.6.3.0 and MSpec play nicely together.

Installing MSpec

Assuming you’ve got R# and StyleCop already installed, you can get MSpec via NuGet:

Option 1 - Package Manager Console
    1. Go to View > Other Windows  > Package Manager Console.
    2. Type in: PM> Install-Package Machine.Specifications

 

Option 2 - NuGet UI
    1. Right-click on the project where you want to reference MSpec.
    2. Select the Online panel and enter mspec in the Search Online box.
    3. Click on the Machine.Specifications package and install.

 

NuGet

 

Once the install is completed, you will find a new packages folder in your solution folder. Drill down to the <Solution Folder>\packages\Machine.Specifications.<version>\tools folder and run the batch file corresponding to your current setup (e.g. InstallResharperRunner.6.0 - VS2010.bat). All you have to do after that is restart Visual Studio and check that the plugin is installed correctly.

 

Go to ReSharper > Options > Environment > Plugins. Both StyleCop and Machine.Specifications checkboxes should be ticked:

 

Plugins

 

Go to ReSharper > Options > Code Inspections > Code Annotations and check Machine.Specifications.Annotations:

Code Annotations

 

Go to ReSharper > Options > Tools > Unit Testing and check Machine.Specifications:

Unit testing providers

 

You are now all set to work with MSpec. If you need further info on MSpec installation please refer to the project’s GitHub page.

 

Removing StyleCop warnings

Once you begin writing your specs, you will start getting a lot of StyleCop warnings:

StyleCop Warnings

 

The easiest way to tell StyleCop to ignore these is to simply add an <auto-generated /> comment in the file header:

StyleCop ignores auto-generated

 

As you can see quite a few warnings have gone but we still need to let R# know about our new naming convention for MSpec files.

 

Fixing R# Naming Style for MSpec

Option 1 - Adding a new file mask

The quick and dirty way to remove R# naming style warnings is to add a new file masks. Go to ReSharper > Options > Code Inspection > Generated Code and click on the Add button under Generated file masks. In the Add New Item dialog enter the file mask. Assuming you have a consistent naming convention for your specs, you can enter something like this:

 

Add New Item

 

Generated file mask

 

Click OK to accept the new file mask and now all naming style warnings should disappear. However there is a proper/better way of doing this as illustrated in this post by Derek Greer. For completeness I will replicate the steps here.

 

Option 2 - Editing Advanced Naming Settings

First go to ReSharper > Options > Languages > C# > C# Naming Style , select Override common settings and then click on the Advance settings button.

 

C# Naming Style Advanced settings

 

In the Advance Naming Settings dialog, click on the Add button:

Advance Naming Settings

 

In the Edit Extended Naming Rule dialog, fill-in the details as show below:

Edit Extended Naming Rule

Affected entity kinds - leave blank.

Affected entities - deselect all then select everything starting with Machine.Specifications.

Access rights - select all.

Static/non-static - select all.

Naming style - click twice on the Add button then select the new entries in turn and check first all_lower then First_upper (under Name Style).

 

Make sure that Enable inspections is ticked and OK to return to your specs. There should be no more naming style warnings. If not try again ;)

 

Code Cleanup and Type Members Layout

The last step is to ensure that you can clean-up both your specs and your source code consistently without one ordering pattern (i.e. layout) interfering with the other. Go to ReSharper > Options > Languages > C # > Type Member Layout, uncheck Use Default Patterns and replace the Custom Patterns with the XML given below which is a merge of both the StyleCop and MSpec R# type member layouts.

 

Merged Type Member Layout

Here's the merged XML (click to expand, double-click to copy):

<?xml version="1.0" encoding="utf-8"?>
<!-- Last updated 24.11.2011 -->
<Patterns xmlns="urn:shemas-jetbrains-com:member-reordering-patterns">
    <!-- Do not reorder COM interfaces -->
    <Pattern>
        <Match>
            <And Weight="2000">
                <Kind Is="interface"/>
                <Or>
                    <HasAttribute CLRName="System.Runtime.InteropServices.InterfaceTypeAttribute"/>
                    <HasAttribute CLRName="System.Runtime.InteropServices.ComImport"/>
                </Or>
            </And>
        </Match>
    </Pattern>
    <!-- Do not reorder P/Invoke structs -->
    <Pattern>
        <Match>
            <And Weight="2000">
                <Or>
                    <Kind Is="struct"/>
                    <Kind Is="class"/>
                </Or>
                <HasAttribute CLRName="System.Runtime.InteropServices.StructLayoutAttribute"/>
            </And>
        </Match>
    </Pattern>
    <!-- Do not reorder P/Invoke classes (called xxxNativeMethods) -->
    <Pattern>
        <Match>
            <And Weight="2000">
                <Kind Is="class"/>
                <Name Is=".*NativeMethods" />
            </And>
        </Match>
    </Pattern>
    <!-- StyleCop pattern -->
    <Pattern RemoveAllRegions="true">
        <Match>
            <Or Weight="1000" >
                <Kind Is="class" />
                <Kind Is="struct" />
                <Kind Is="interface"/>
            </Or>
        </Match>
        <!-- constants and fields -->
        <Entry>
            <Match>
                <Or>
                    <Kind Is="constant"/>
                    <Kind Is="field"/>
                </Or>
            </Match>
            <Sort>
                <Access Order="public internal protected-internal protected private"/>
                <Kind Order="constant field"/>
                <Readonly/>
                <Static/>
                <Name/>
            </Sort>
            <!--<Group Region="Constants and Fields"/>-->
        </Entry>
        <!-- constructors and destructors -->
        <Entry>
            <Match>
                <Or Weight="200">
                    <Kind Is="constructor"/>
                    <Kind Is="destructor"/>
                </Or>
            </Match>
            <Sort>
                <Static/>
                <Kind Order="constructor destructor"/>
                <Access Order="public internal protected-internal protected private"/>
            </Sort>
            <!--<Group Region="Constructors and Destructors"/>-->
        </Entry>
        <!-- delegates -->
        <Entry>
            <Match>
                <Kind Is="delegate"/>
            </Match>
            <Sort>
                <Access Order="public internal protected-internal protected private" />
                <Static />
                <Name/>
            </Sort>
            <!--<Group Region="Delegates"/>-->
        </Entry>
        <!-- public events -->
        <Entry>
            <Match>
                <And>
                    <Kind Is="event"/>
                    <Access Is="public"/>
                </And>
            </Match>
            <Sort>
                <Access Order="public" />
                <Static />
                <Name/>
            </Sort>
            <!--<Group Region="Public Events"/>-->
        </Entry>
        <!-- interface events -->
        <Entry>
            <Match>
                <And>
                    <Kind Is="event"/>
                    <ImplementsInterface/>
                </And>
            </Match>
            <Sort>
                <ImplementsInterface Immediate="true"/>
                <Name/>
            </Sort>
            <!--<Group Region="Explicit Interface Events" />-->
        </Entry>
        <!-- other events -->
        <Entry>
            <Match>
                <Kind Is="event"/>
            </Match>
            <Sort>
                <Access Order="public internal protected-internal protected private" />
                <Static />
                <Name/>
            </Sort>
            <!--<Group Region="Events"/>--></Entry>
        <!-- enum -->
        <Entry>
            <Match>
                <Kind Is="enum"/>
            </Match>
            <Sort>
                <Access Order="public internal protected-internal protected private" />
                <Name/>
            </Sort>
            <!--<Group Region="Enums"/>-->
        </Entry>
        <!-- interfaces -->
        <Entry>
            <Match>
                <Kind Is="interface" />
            </Match>
            <Sort>
                <Access Order="public internal protected-internal protected private" />
                <Name/>
            </Sort>
            <!--<Group Region="Interfaces"/>-->
        </Entry>
        <!-- public properties -->
        <Entry>
            <Match>
                <And>
                    <Kind Is="property"/>
                    <Access Is="public"/>
                </And>
            </Match>
            <Sort>
                <Access Order="public"/>
                <Static/>
                <Name/>
            </Sort>
            <!--<Group Region="Public Properties"/>-->
        </Entry>
        <!-- interface properties -->
        <Entry>
            <Match>
                <And>
                    <Kind Is="property"/>
                    <ImplementsInterface/>
                </And>
            </Match>
            <Sort>
                <ImplementsInterface Immediate="true"/>
                <Name/>
            </Sort>
            <!--<Group Region="Explicit Interface Properties" />-->
        </Entry>
        <!-- other properties -->
        <Entry>
            <Match>
                <Kind Is="property"/>
            </Match>
            <Sort>
                <Access Order="public internal protected-internal protected private"/>
                <Static/>
                <Name/>
            </Sort>
            <!--<Group Region="Properties"/>-->
        </Entry>
        <!-- public indexers -->
        <Entry>
            <Match>
                <And>
                    <Kind Is="indexer" Weight="1000" />
                    <Access Is="public"/>
                </And>
            </Match>
            <Sort>
                <Access Order="public" />
                <Static/>
                <Name/>
            </Sort>
            <!--<Group Region="Public Indexers"/>-->
        </Entry>
        <!-- interface indexers -->
        <Entry>
            <Match>
                <And>
                    <Kind Is="indexer" Weight="1000"/>
                    <ImplementsInterface/>
                </And>
            </Match>
            <Sort>
                <ImplementsInterface Immediate="true"/>
                <Name/>
            </Sort>
            <!--<Group Region="Explicit Interface Indexers" />-->
        </Entry>
        <!-- other indexers -->
        <Entry>
            <Match>
                <Kind Is="indexer" Weight="1000" />
            </Match>
            <Sort>
                <Access Order="public internal protected-internal protected private" />
                <Static/>
                <Name/>
            </Sort>
            <!--<Group Region="Indexers"/>-->
        </Entry>
        <!-- public methods -->
        <Entry>
            <Match>
                <And>
                    <Kind Is="method"/>
                    <Access Is="public"/>
                </And>
            </Match>
            <Sort>
                <Access Order="public"/>
                <Static/>
                <Name/>
            </Sort>
            <!--<Group Region="Public Methods"/>-->
        </Entry>
        <!-- interface methods -->
        <Entry>
            <Match>
                <And>
                    <Kind Is="method"/>
                    <ImplementsInterface/>
                </And>
            </Match>
            <Sort>
                <ImplementsInterface Immediate="true"/>
                <Name/>
            </Sort>
            <!--<Group Region="Explicit Interface Methods" />-->
        </Entry>
        <!-- other methods -->
        <Entry>
            <Match>
                <Kind Is="method"/>
            </Match>
            <Sort>
                <Access Order="public internal protected-internal protected private"/>
                <Static/>
                <Name/>
            </Sort>
            <!--<Group Region="Methods"/>-->
        </Entry>
        <!-- operators -->
        <Entry>
            <Match>
                <Kind Is="operator"/>
            </Match>
            <Sort>
                <Access Order="public internal protected-internal protected private" />
                <Static/>
                <Name/>
            </Sort>
            <!--<Group Region="Operators"/>-->
        </Entry>
        <!-- Nested structs -->
        <Entry>
            <Match>
                <Kind Is="struct"	Weight="600" />
            </Match>
            <Sort>
                <Static />
                <Access Order="public internal protected-internal protected private" />
                <Name/>
            </Sort>
        </Entry>
        <!-- Nested classes -->
        <Entry>
            <Match>
                <Kind Is="class"	Weight="700" />
            </Match>
            <Sort>
                <Static />
                <Access Order="public internal protected-internal protected private" />
                <Name/>
            </Sort>
        </Entry>
        <!-- all other members -->
        <Entry/>
    </Pattern>
    <!-- MSpec pattern -->
    <Pattern RemoveAllRegions="true">
        <Match>
            <And Weight="100">
                <Kind Is="class"/>
                <Or>
                    <HasAttribute CLRName="Machine.Specifications.SubjectAttribute"	Inherit="true"/>
                    <Name Is="^when_.+"	IgnoreCase="true" />
                </Or>
            </And>
        </Match>
        <Entry>
            <Match>
                <And>
                    <Kind Is="field"/>
                    <Or>
                        <Access Is="protected"/>
                        <Static/>
                    </Or>
                </And>
            </Match>
        </Entry>
        <Entry>
            <Match>
                <And>
                    <Kind Is="field"/>
                    <Name Is="^context(_once)?$"	IgnoreCase="true"/>
                </And>
            </Match>
        </Entry>
        <Entry>
            <Match>
                <And>
                    <Kind Is="field"/>
                    <Name Is="^of$"	IgnoreCase="true"/>
                </And>
            </Match>
        </Entry>
        <Entry>
            <Match>
                <And>
                    <Kind Is="field"/>
                    <Name Is="^after(_all)?$"	IgnoreCase="true"/>
                </And>
            </Match>
        </Entry>
        <Entry>
            <Match>
                <And>
                    <Kind Is="field"/>
                    <Name Is="^should_.*$"	IgnoreCase="true"/>
                </And>
            </Match>
        </Entry>
        <Entry>
            <Match>
                <And>
                    <Kind Is="field"/>
                    <Not>
                        <Static/>
                    </Not>
                </And>
            </Match>
        </Entry>
        <!-- All other members -->
        <Entry/>
    </Pattern>
</Patterns>

You should now be able to enjoy writing your specs without squiggly lines all over and also perform code clean-ups (CTRL + E + F) smoothly.


Comments are closed
© Copyright 2012 TheBooleanFrog Powered by: BlogEngine.NET|Credits|Subscribe via RSS

Follow

twitter linkedin linkedin rss

TheBooleanFrog

Programming sticky notes and other distractions...