TagAlong: ReSharper Plugin
This is my first attempt at creating a plugin for ReSharper. It seems very daunting at first. It's taken me a few hours to actually figure out the base of what I wanted to do.
This isn't due to poor documentation; but unfamiliarity with how. Once I see how; the documents make a lot of sense... Catch 22 in that area.
Aside from blogging helping cement stuff mentally for myself; I hope this can streamline someone else's efforts to create ReSharper plugins.
At work on the µObjects project, we use fakes. Largely because UWP doens't support mocking frameworks. This isn't to get into the Mock vs Fake argument; but I prefer fakes now. I feel they're keeping my unit tests much cleaner.
With the fakes we use at work; part of it is a Builder
for the fake to configure the interface. I'll try to get the supporting classes into a repo soon. Not sure I can do that, or if I need to re-implement at home.
Anyway - A fake implements an interface. Has some helper stuff in the builder. This takes us anywhere from 5 - 30 minutes to get into place. I want a plug in that I can Alt-Enter
and select "Create Fake" and have it all done for me.
We have templates for a lot of the pieces, and it still takes the 5-30 minutes. This will take seconds, potentially saving hours a week.
If this works well for us; I'll probably create more aspects to the plug in. It's really around the style we've developed so the plugin won't be available for broader use. I want the plugin for some more intelligence that the Live Templates aren't providing. Nor would I expect them to.
I'm following the ReSharper DevGuide as my starting point.
Starting at the How To links to a sample plugin which doesn't build for me. shrug These things happen; but it provided enough information to get me a step closer in some spikes.
I like including the steps from guides instead of a bunch of "Go Here". There's not a lot I add; and some of the steps are a bit long and detailed. I don't want to be copy/pasting things into this.
Skipping ahead a small amount - Create the Project!.
Package up the plugin - Create a NuGet Package for the Plugin.
Now to enable debugging - Set Up Environment.
I'm having a bit of trouble with the environment configuration.
Before you can debug the plugin, you must initially install it to the Visual Studio hive you use for debugging. Do this via ReSharper | Extension Manager…. Note that you will need to specify the folder with the plugin as a custom source. You can do this via ReSharper | Options… | Extension Manager | Add.
Which folder? The one with the nupkg
? Doing that doesn't get the plugin to show up in the Extension Manager...
Which seems to have been because I had the version wrong. Using TestCop as my example; the Dependency for the Nuget Package is
<dependency id="Wave" version="[11.0.0]"/>
And BAM! Shows up.
My plan
I'm going to create a Context Action that will trigger on interfaces... I hope.
That's phase one - Get my Context Action to show.
... Which I'm having a lot of trouble with...
Huh... I think I needed a ZoneMarker
. Which isn't clearly spelled out anywhere. Part of why I'm blogging this.
The information of a zone marker can be found in the guide at the How to Define a Zone Marker.
This was linked to from the TroubleShooting page.
It's a temp solution to put an empty class at the highest common namespace.
Ensure the plugin has a Zone marker defined in the project’s root namespace (e.g. if the project has code in the Foo.Bar and Foo.Bar.Quux namespaces, the zone marker should live in the Foo.Bar.ZoneMarker class).
The class can be empty; and looks like this for me.
[ZoneMarker]
public class ZoneMarker
{
}
A quick reinstall as specified in the Set Up Environment
IMPORTANT! It’s not necessary to reinstall the plugin each time you introduce the changes to your plugin; simple copying of the .dll will be enough in most cases (see the next steps). Nevertheless, if your changes affect any integration points, such as actions, menus, or others, you MUST reinstall the plugin.
A Context Action is an action integration point it requires a reinstall.
Now that I've done that - IT SHOWS!
VERY EXCITING! ... for me. :)
Unless I'm doing something wrong - I think I need to uninstall/install my extension everytime to test it. Sad; but OK.
I'm really wishing there was a good reference of how to generate code... :\
I'm working on reverse engineering the "Create Derived Type" ContextAction that ReSharper has built in for reference on doing this myself. It does mostly what I want to do - at least at a base level; it is. I need to extend what it does; but it'll be a start once I understand it.
This is some black magic syntax. I feel like I need to read the Lexi section of a compiler book to understand it.
I've gotten back to the plugin when I uploaded IMock. The reason for this is that the generation of the code is a pain if you don't have at least templates. Even templates take a bit of time as each method has to be done via a template.
The Reshaper plugin (oh yeah) allows the entire builder class to be generated. If we compare to no templates - this will save days of work in a normal month using this Mock framework.
I know it'll probably count as a hit against IMock that it takes so much set up - but it's clean and makes test creation go really fast.
Over all - It saves time, even if you have to do it manually.
Back to the plugin - I was slogging through it... pain in the ass, didn't understand a bunch of what I had crammed in.
I spent hours getting it into microObjects - and it made sense. What it was doing and how was a lot easier to read. Maybe due to using the code more... I'm pretty sure it was around the fact that I only had to focus on one 'level' of the code at at time. I didn't even have to see the other levels.
This caused a much lighter cognitive load while thinking about the code. This makes it easier to understand; easier to see better solutions. I'm happy with the change over.
The change also allowed me to get the other 1/2 implemented in less than 2 hours. Took me about 3 to extract all the objects; and then 2 to get it finished.
That's right - Finished.
The plugin isn't in some partial state; it'll produce a full MockClass from an interface.
My team would have loved this 6 months ago... hehe
Anyway; I'll be working to get this compiled and uploaded as part of IMock, not a separate repo as was my original plan. It's tied pretty tightly to what that is.
Anyway - HELL YEAH! Complete!