Stringless NMock2 Method names with C#3 extension methods – revisited
Today, I got to revisit an old but nifty hack to code around the fact that NMock2 uses strings for method names (or, you could supply a MethodInfo, clumsy and cumbersome) - this hack has been discovered, developed and distributed many times. A quick google turns up this which I will just take a bit further:
Now, being able to write
Expect.Once.
On(hand).Method<Iron>(hand.TouchIron).
With(Is.Anything).
Will(Throw.Exception(new BurnException()));
Is all good, even if it's a bit annoying to have to specify return type of the mocked call (Iron) but I was more annoyed by the all-pervasive duplication of mock instance.
So, Instead, I give you the slightly revised syntax:
Expect.Once.
On<Iron>(hand.TouchIron).
With(Is.Anything).
Will(Throw.Exception(new BurnException()));
and here's the extension method code to accomplish it:
private static IArgumentSyntax BuildArgumentSyntax(Delegate d, IReceiverSyntax rcv)
{
MethodInfo mi = d.Method;
object target = d.Target;
IArgumentSyntax argumentSyntax = rcv.On(target).Method(mi.Name);
return argumentSyntax;
}
public static IArgumentSyntax On(this IReceiverSyntax rcv, Action d)
{
return BuildArgumentSyntax(d, rcv);
}
public static IArgumentSyntax On<TResult>(this IReceiverSyntax rcv, Func<TResult> d)
{
return BuildArgumentSyntax(d, rcv);
}
// ... fill in more overloads as needed...
As you can see, you need to supply an overload for every combination of parameter list and return type you want to be able to mock this way.
Happy mocking!
/Stefan
Introducing StyleCop on Legacy Projects using StyleCop for ReSharper
Recently, I've been working with introducing StyleCop on some legacy projects using the StyleCop for ReSharper plug-in.
This Blog aims to collect my findings, and also give some idea of what one can expect from using ReSharper to achieve StyleCop compliance.
First, I'll go thru how I auto-cleaned issues in one project, and after that I'll give some numbers from a complete solution.
A Single Legacy Project
The single legacy project was a measly 16 .cs files big, of which 2 were designer files. Just turning StyleCop onto this yielded 370 issues.
While this may come off as deterring at first, this blog is about how to use StyleCop for ReSharper to bring that down considerably.
Excluding designer files and generated files
Since Visual Studio .Designer.cs files aren't StyleCop compliant (no VS templates are) you probably want to exclude those from StyleCop.
These are your options:
- Doing it project-wide from the "Detailed Settings" on the "Rules" tab of the StyleCop Project Settings.
- Setting it per designer file by including a
//<auto-generated />
comment in the file header.
Handling Documentation Issues
First of all, you need to decide on how to handle the documentation issues, which normally will account for around half the warnings.
These are your options:
- Temporarily turn off all StyleCop rules but the documentation rules, and remedy those manually before going ahead with cleaning up the rest of the code.
- Permanently turn off all StyleCop documentation rules, and concentrate on the code.
- Auto-generate documentation tags by doing a "Code Cleanup" with all documentation cleanup modules enabled.
I would not recommend number three, as it will pollute your code with less-than-meaningful documentation comments.
Handling Header Formatting Documentation Issues
StyleCop is quite strict on how the file header should be formatted. It needs to have the filename in a copyright element, and you're not allowed to wrap the header in a region, for example.
To fix the header, you have these options:
- If your policy dictates an StyleCop-incompatible header content, permanently disable StyleCop rules concerning file header.
- If your policy dictates you have a multi-line copyright + licence text, manually Copy+Paste a compliant file header into each file, applying the quick fix to update the file="" attribute of the copyright element.
- If your policy allows for a single-line copyright statement, let the Stylecop plugin create those for you on running Code Cleanup. Fill in 'Company Information' in the StyleCop Settings, enable "Update file header" and let the StyleCop plugin "Replace entire header" in the Code Cleanup settings.
Taking these measures brought down the number of issues to 302.
Configuring StyleCop Code Cleanup
You need to configure ReSharper to have the built-in Code formatting help auto-format for StyleCop compliance.
Fortunately, the StyleCop for ReSharper comes with a StyleCopCodeStyle.xml resharper codestyle export, that you can import from the ReSharper options dialog.
A couple of notes on applying the StyleCopCodeStyle.xml code styles:
- I set "Blank lines between using groups" to zero; otherwise I get the "usings should be sorted alphabetically" issue as the "sort usings" only do so within using groups.
- I set "Wrap Lines" to zero, as StyleCop really doesn't like that.
- And of course, you need re-specify your StyleCop and Code Cleanup settings for documentation and header file fixes as per above.
Running Code Cleanup
After running the Code Cleanup with these settings and rebuilt, I'm now down to 24 issues - less than a tentht of the original number of warnings.
Running Code Cleanup a second time and rebuilding yields 21 warnings, a third cleanup round gives 16, and finally, doing it a fourth time and rebuilding I land on 10 issues.
This odd behaviour is because each cleanup round only adresses one of several potential issues per code block, and in the process, they sometime introduce new issues.
So just run Code Cleanup and rebuild until the number of issues stabilizes.
While working with this, the StyleCop Fixes page is an invaluable resource to debug your ReSharper Code Cleanup settings.
Manual fixes
The last 10 issues were actual errors or issues where there isn't enough context for Code Cleanup to do automatic refactorings. All of them were easily remedied given the available ReSharper refactorings:
- SA1401: Public fields should be exposed thru properties – if there is a good reason for exposing public fields directly, this warning can be suppressed using the suppression quickfix.
- SA1305: No Hungarian notation-like variable names.
- SA1300: Function names should begin with upper-case letter.
All in all, there were automatic or semi-automatic fixes for all issues.
A Full Solution
For my second test, I used a production solution consisting of 26 projects, all with roughly the same code content as my single project.
Turning StyleCop on yielded 5500+ issues.
Fixing Designer files, Documentation and header issues brought this down to 2924 issues.
- If you want to set StyleCop settings (exclude documentation, no designer files et c) on the full solution, copy/move a suitable Settings.StyleCop into the solution directory. The default for StyleCop is to try and merge the local project Settings.Stylecop with the one in the parent directory.
Applying Code Cleanup iteratively took me down to 264, 261, 256 and finally 255 issues.
During both this test and the single project test I experienced 'hiccups' where a certain issue weren't fixed by a global Code Cleanup, but redoing it on the single file or using the quickfix would.
Conclusion
By using the StyleCop for ReSharper plugin, introducing StyleCop on legacy projects can be reasonably painless. The main part is to comply with the documentation rules; once these are handled, the issues remaining can be fixed reasonably simple and with a small amount of developer work, even for large solutions.
If you have questions, think there is something I've ommitted in this article or just want to share your experiences or good links with the world, please don't hesitate to comment.
Happy refactoring!
Stefan Andersson
On Revisions, tags and branches
In light of some confusion in the wake of the 0.6.5 release of OpenSimulator, I just thought I'd share a couple of good-to-know points about SVN versioning;
In an SVN repo, the 'revision' is a discrete version of the software. But; the revision number is not an indication of sequential functional increment.
Revisions are based on a revision before it, but that does not have to be the revision immediately before it.
The revision number counter is global to the svn repository, hence it is upped whenever somebody does something within the repo, regardless of what branch the thing happens to.
An example:
- I commit something to trunk, the rev number is upped to, say, 1337, and my new version is given that number.
- I now branch trunk into /branches/mybranch. I do this by doing a remote copy of trunk. This copy of trunk, although identical to 1337, is a new version and is thus given the revision number 1338, the first revision on the new branch.
- Now I commit a number of changes to trunk, spinning past 1339, 1340, 1341 and 1342 - each being separate versions but on the branch called /trunk (think of it as paths)
Now, if I commit some minor change to /branches/mybranch, what revision number will it get? You guessed it - 1343.
If I now commit something to /trunk again, it will get 1344. I then commit something to the really really old branch /branches/reallyoldbranch that was based on, say, revision 666. It will now get 1345.
So, my point is: you should never talk about revision numbers when your're trying to convey an idea of some kind of sequential advancement of state.
Ie, in my example, 1344 is probably the one reflecting the most development, 1343 is essentially based on 1337 and 1345, currently the highest rev number, could basically be six months old, with just a minor modification.
Now on to tags:
Trunk, branches and tags are really all one thing: paths. The only real difference is by convention: there is a certain path called /trunk that serves a certain purpose, namely to be the focal point for developers. There is a certain name used for paths other than trunk, and that is "branches". Some branches by convention aren't meant to be modified, but serve as snapshots of a point in time - they are called "tags".
But to the server, they are all revisions along differerent link paths. There is really nothing stopping you from committing to a tag - it's just the svn client will be reluctant to do so, as it's aware of the convention.
Keep this in mind, when referring to a 'revision' - it might be on a totally different path, so be sure to mention what path you're really talking about. specifying "trunk, between revision 1343 and 1780" or "0.6.2 post-fixes, between revision 1764 and 2006" again lets you compare revision numbers to indicate advancement of state.
Also, don't tell people to check a certain revision out, unless you mean exactly that code snapshot. If you want them to check out a certain version, tell them the logical path to it instead.
I hope this has cleared any potential confusion up.
Top ten ways to know you are not doing agile
Alistair Cockburn ('cooburn') is one of my heroes; here's a thought-provoking list to match your team against:
http://alistair.cockburn.us/Top+ten+ways+to+know+you+are+not+doing+agile
Refactoring Tactics Primer
Introduction
In this article I will show how to employ some relatively advanced code refactoring tactics to change a reasonably hairy piece of spaghetti code into something a bit more structured.
Basic familiarity with the JetBrains ReSharper tool is required.
Background
The code in this sample reflects an actual piece of code that a colleague of mine got handed to him. Amongst other abominations, it employed the 'transferring values in and out of Windows Forms by getting and setting public fields on an global static class' anti-pattern. He realized that the code actually introduced a bug (since the static fields would retain their values between subsequent calls) so I thought I'd show him how to wrestle out of some of the more nasty bits of the code. After doing that, I figured I'd write this article so that the world brain could benefit from it.
Instructions
Download the RefactoringPrimer.zip and extract and load the Visual Studio 2008 solution Seminar1.sln, make sure you have ReSharper handy, and follow the walkthrough below.
The solution is split into six steps, Step 1 being the original spaghetti code, and Step 6 the final result.
The Scenario is built around an application (Program) that calls up a (faked) Windows Form (FakeForm), and uses a static utility (Util) class to pass initial values and fetch returned data.
Each solution project corresponds to the starting point in each step, and builds a console project that when run tries to call up forms twice, each time emulating a user entering some data, and reports 'wrong: using tainted maxValue' or 'correct: using default maxValue'.
Points of Interest
This walkthrough is really only a primer to what can be done with taking a "automated refactoring tactics" approach; "tactics" referring to laying out a 'strategy', a chain of automated refactorings to get from a code state a to a code state b.
To create this particular set of refactoring tactics, I made extensive use of scratch refactoring, which is something I've found to be very useful.
Walkthrough
Step1 - Deciding what to break out
- Manually create a public inner class called 'FormData' inside the Utils class.
static class Utils { public class FormData { } private const int DEFAULT_MAX_VALUE = 5; public static int MinValue = 1; public static int MaxValue = DEFAULT_MAX_VALUE; public static int MeanValue = 10; - Right-click on the MinValue member field, choose "Refactor", then "Move". Check static fields MinValue, MeanValue and MaxValue, and specify Step1.FormData as the target. Press "Next". After the move, note that DEFAULT_MAX_DATA is accessible, since FormData is an inner class. Also, inspect
FakeFormandProgramto see the updated references. - Run and show wrong result
From now on, I will not write out the 'right-click', "Refactor" or "Click Next" et c - if the istructions aren't obvious to you, I recommend you spend some time familiarize yourself with ReSharper. Either that, or place a request for clarification in the comments.
Step2 - Breaking out of the static cage
- "Copy Type"
Utils.FormDatato InstanceFormData - it will also be an inner class. - Remove all static declarations on the copied type -this will become our 'new' FormData.
public class InstanceFormData { public int MinValue = 1; public int MaxValue = DEFAULT_MAX_VALUE; public int MeanValue = 10; } - "Move" InstanceFormData to "Outer scope" giving it the new name "FormData"
- The refactoring tool will complain that
DEFAULT_MAX_VALUEwill no longer be accessible. TurnDEFAULT_MAX_VALUEpublic and hit 'Refresh' - Change 'internal' on new FormData to "public" (or you will get a build error when we do the manual switch later)
public class FormData { public int MinValue = 1; - Manually remove inner FormData type definition and replace with a static Singleton field initializer:
static class Utils { public static FormData FormData = new FormData(); public const int DEFAULT_MAX_VALUE = 5; public static bool IsDefaultMaxValue( int val ) { return val == DEFAULT_MAX_VALUE; } public static bool TestMinGreaterThan3() { return FormData.MinValue > 3; } } public class FormData { public int MinValue = 1; public int MaxValue = Utils.DEFAULT_MAX_VALUE; public int MeanValue = 10; } - Run and show wrong result - we're still running on the same instance.
Step3 - Passing the temporary singleton around
- "Introduce field" m_formData on FakeForm, initialized in constructor.
- "Introduce Parameter" formData on m_formData initializer.
- Manually change FakeForm constructor member initializations to
m_min = formData.MinValue; m_mean = formData.MeanValue; m_max = formData.MaxValue;
(remember that the member fields are faking textboxes)
- "Safe Delete" all unused (greyed out) constructor parameters
- "Introduce Parameter" formData on TestMinGreaterThan3
static class Utils { public static FormData FormData = new FormData(); public const int DEFAULT_MAX_VALUE = 5; public static bool IsDefaultMaxValue( int val ) { return val == DEFAULT_MAX_VALUE; } public static bool TestMinGreaterThan3(FormData formData) { return formData.MinValue > 3; } } - "Move" static method TestMinGreaterThan3 to FormData
- "Make method non-static" on TestMinGreaterThan3
public class FormData
{
public int MinValue = 1;
public int MaxValue = Utils.DEFAULT_MAX_VALUE;
public int MeanValue = 10;
public bool TestMinGreaterThan3()
{
return MinValue > 3;
}
}
Step4 - Getting rid of the temporary singleton
- "Introduce variable" formData on first Utils.FormData in Run()
FormData formData = Utils.FormData; FakeForm a = new FakeForm(formData);
- Manually Change Utils.FormData to new FormData();
FormData formData = new FormData(); FakeForm a = new FakeForm(formData);
- Manually add another initializer.'
FormData formData = new FormData(); FakeForm a = new FakeForm(formData); bool result = a.RunCase1(3, 4); // Setting min and max formData = new FormData(); FakeForm b = new FakeForm(formData); - Run and revel in succesful result
Step5 - Some final cleanup
While we've fixed the main issue, there is still some simple refactoring that can be done to give that "cleaner, fresher feeling".
- "Inline method" SetMeanValue() in FakeForm
- "Rename" FakeForm method SetStatics() to SetFormData
- "Move" FormData to its own file FormData.cs
Step6 - The final result
We have now moved from a spaghetti code mess to nice decoupled code, and hopefully you have gotten a glimpse of what chaining automated refactorings can do for your code.
If you've done this excercise and found it worthwhile, please consider giving me your feedback so I can make this article even better - also, illustrative screenshots taken along the way would be greatly appreciated!
Happy tinkering!
Nunit, Custom CategoryAttribute and ReSharper testrunner
JetBrains recently announced the new ReSharper 4.5.
One of the bugs that was fixed in this release, is that the testrunner now correctly displays custom NUnit categories based on CustomAttribute.
Custom NUnit categories is very useful for grouping tests in the same solution, so that you can manually choose what group to run (unit tests, database tests, system tests) - or set a job up that tests using the /exclude and /include command line switches on the runner.
Of course, various other NUnit runners have been honouring subclassed categories since the feature was introduced in NUnit 2.4, but it's nice to have it in my favourite runner.
Uninstalling a Previous Version from an MSI
It was absurdly hard to figure out how to auto-uninstall a Previous Version from an MSI, so I'm just adding a link here in the hope that it will help the world find that link easier.
Basically:
- In the Setup project properties, there's a property "Version" (probably 1.0.0)
- change it to any value e.g. 1.0.1 (do note the 3-part, in assemblies, versions are 4-part)
- Now it will ask to change product code automatically - just click "yes"
- Build the new relase & install it.
- The previous verison will get uninstalled first.
Why is IPN Responding with ‘INVALID’?
If you're doing an PayPal IPN implementation, you should be careful to set the right encoding for IPN (You probably want UTF-8) - otherwise international characters will be read in one form from the "subscr_signup", "subscr_payment" or "web_accept" form data and written in another form in the "_notify-validate" response - which will make the validation fail.