Friday, January 27, 2012

A nice little trick with FluentAssertions

I love using FluentAssertions when writing tests for my code, it just makes the code so expressive in plain language. Recently I’ve been working on tests which involve the testing of lots of properties on a test result, and was looking for a way to remove a lot of the repetition involved.

Usually when asserting the properties on a test result, you can do it in three different ways. If I have my test class defined as below:

[TestFixture]
public class MyTestFixture
{
    private MyClass _subject; 
    private MyOtherClass _result;
 
    [SetUp]
    public void ExecuteTest() 
    { 
        _subject = new MyClass(); 
        _subject.Initialise(/*.. Some parameters here ..*/); 
        _result = _subject.SomeOperation();
    }
}

Then I can test the results as follows:

A. Assert all the properties in a test method

    [Test]
    public void ThePropertiesAreSet()
    {
        _result.First.Should().Be("Paula Bean");
        _result.Second.Should().Be("Brillant!");
    }

This is probably the usual way people do this. However, if the first test fails, the second test will never run, and we'll never know if our test method set the second result correctly or not, so we are lacking information as to the overall state of the test. Secondly, as the number of properties to test increases, you end up with a lot of visual noise, although Intellisense will at least take some of the effort out of creating the noise.

B. Assert the properties in a test method per property

    [Test]
    public void TheFirstPropertyIsSet()
    {
        _result.First.Should().Be("Paula Bean");
    }
 
    [Test]
    public void TheSecondPropertyIsSet()
    {
        _result.Second.Should().Be("Brillant!");
    }

With this approach, we now know if the setting of _result.Second was successful, even if _result.First failed. This extra information does come at the expense of more visual noise (the addition of another test method). Also, it allows you to really game the system if you get rewarded for the number of tests in your project :-)

C. Implement IEquatable

As the number of properties on MyOtherClass go up, you'll find a lot of code appearing in the test method. You can remove this by implemeting IEquatable<MyOtherClass> on MyOtherClass:

public class MyOtherClass : IEquatable<MyOtherClass>
{
    public override bool Equals(MyOtherClass other)
    {
        return this.First == other.First && this.Second == other.Second;
    }
}

(please note you should also really implement Object.Equals and Object.GetHashCode if you're going to use IEquatable, and for brevity, I've missed out a lot of the basic implementation of IEquatable<T>)

The result of this is that our test method now becomes:

    [Test]
    public void TheFirstPropertyIsSet()
    {
        MyOtherClass expected = new MyOtherClass { First = "Paula Bean", Second = "Brillant!" };
        _result.Should().Be(expected);
    }

Much cleaner and very expressive, and you'll probably find your code benefits elsewhere from having implementations of IEquatable<T>; but you do have to write that implementation (and perhaps unit test it too!). Yet more code...

This finally leads me to my point:

D. Use anonymous classes and FluentAssertion's AllProperties

How's this for simplicity?

    [Test]
    public void TheFirstPropertyIsSet()
    {
        _result.ShouldHave().AllProperties().EqualTo(new { First = "Paula Bean", Second = "Brillant!" });
    }

ShouldHave().AllProperties() does all the hard work of checking the properties. You can also use SharedProperties() if you only need to test a subset of the properties, and add IncludeNestedObjects if you have a more complex object model.

P.S. I love the story of the Brillant Paula Bean. It confirms all your prejudices about contractors.

Wednesday, January 11, 2012

Adobe Lightroom 4 Beta is out!

Adobe Lightroom 4I’m looking forward to this. I’ve been a user of Lightroom since it first came out as version one, and it’s been indispensible for managing my growing photo collection (I passed the 10000 mark last year).

I’m particularly excited by the long-awaited introduction of proper geocoding support. I bought a GPS logger a year or two ago, and use Dirk Stichling’s My Tracks to add geotag my photos prior to importing them into Lightroom. When I export from Lightroom to iPhoto, the geotags are picked up and displayed nicely in the Places section of iPhoto (and on the iPhone and iPad). However, this only works when importing photos – existing photos cannot be geotagged. Jeffrey Friedl has written a plugin for Lightroom that achieves this, after a fashion, but I prefer my metadata to reside within embedded metadata, rather than in shadow files which are then written on export; and although My Tracks is a good application, I would prefer to have fewer steps in the overall process.

Of course, the ideal would be for Canon to release an accessory that geotags photos when they are taken, but for the moment, they seem to be preferring to take the third-party route.

Friday, January 06, 2012

New Year, New Resolutions

よいお年をお迎えください。

In other words, happy new year!

As far as making and keeping new resolutions go, I’d already failed miserably by January 2nd, probably setting a new low. The resolution was to take a photograph everyday and upload it to Flickr/Facebook, but that just didn’t happen. In fact, I haven’t picked up my camera for a week or two, and only used the camera in my phone to play around with Photosynth, which looks completely out of place on an iPhone, having been built for a Windows-based phone with no effort made to translate the UI design, but nevertheless, works very well.

However, the new year does afford me the chance to indulge in some spring cleaning, even if we are in the early throes of summer here in the Lucky Country. In particular, now that I am back at work, it means opening up the computer case, and having some fun with a rather large air compressor to remove all the dust that has accumulated since the PC was assembled. It also means that I can finally give it a good formatting and install everything afresh, something which every PC user should do at least annually.

Clean ALL the things!This of course reminds me just how many applications I have downloaded and installed in the past year. Just installing Windows 7 with all the layers upon layers of patches takes about half a day, and our internet connection at work feels much slower than my home internet connection.

To give you an idea of just how much stuff your typical Windows developer needs to make it through the day, here’s an approximate list. So far it’s taken me a whole day to download and install this lot, and I’m still finding those useful little apps that you forget aren’t included out-of-the-box.

System

  • 7-Zip – beats WinZip for compression any day;
  • DropBox – file synchronisation across almost any device;
  • Google Chrome – the choice of most developers;
  • Mozilla Firefox – the chose of most other developers;
  • Skype – for keeping in touch with our other offices around the world;
  • Virtual CloneDrive – for mounting all those application installation ISOs;
  • Windows Live Essentials – Mail, Messenger, and of course, Writer (which no self-respecting blogger should be without – definitely one of the most useful products to come out of Redmond);

Business Applications

Developer Tools

  • Beyond Compare – the best diff tool that I’ve tried (WinMerge is free and also very good, but I just prefer BC);
  • CruiseControl.NET – nothing inspires confidence in your day’s work like a row of green lights confirming that it compiles, the tests ran successfully, and the installation package is ready to be shipped;
  • Fiddler – if you have to send data across the network, you need this tool;
  • Notepad++ – syntax highlighting for almost every language out there, and tabbed windows too;
  • Smtp4Dev - for testing the sending of emails;
  • SQL Server Compact – for when the application you are developing will not need a full-blown database server;
  • SQL Server Express – for when application you are developing will need a full-blown database server;
  • Subversion (command-line, GUI, and IDE integration) – who wants to be a tightrope walker without a safety net?
  • Visual Studio – where I spend 95% of my time:
  • Windows 7 SDK – essential developer tools;
  • Silverlight – for rich web client development;
  • Silverlight Toolkit – the bits that Microsoft forgot in Silverlight
  • Expression Blend SDK – another set of bits that Microsoft forgot in Silverlight