Painless TDD – Strip away your dependencies!

May 14th, 2012

Have you ever come across the problem where, in order to construct the object you are trying to test, you end up creating massive scaffolding code just to pass to the constructor? Perhaps an example is in order:

class ChessGame {
    // Some instance variables
 
    public ChessGame (Player player1, Player player2, int timeLimit) {
        this.player1 = player1;
        this.player2 = player2;
        this.timeLimit = timeLimit;
    }
 
    public void playGame() {...}
}
 
class ChessGameTest {
    @Test
    public void testChessGamePlaysForXseconds () throws Exception {
        Player player1 = createMock(Player.class);
        Player player2 = createMock(Player.class);
 
        Handicap handicap1 = new Handicap(10, Rules.Standard);
        Handicap handicap2 = new Handicap(4,  Rules.Standard);
 
        expect(player1.getName()).andReturn("D. Duck");
        expect(player2.getName()).andReturn("M. Mouse");
 
        expect(player1.getHandicap()).andReturn(handicap1);
        expect(player2.getHandicap()).andReturn(handicap2);
 
        replayAll();
 
        new ChessGame(player1, player2, 10).playGame();
 
        // Assertions ....
    }
}

The problem here is that we’ve specified dependencies on far too many objects and values! By asking for two Player objects, you’re essentially saying “give me two objects which have names, ages, total scores, rankings, biographies, etc… and which also have very detailed Handicap information”.

Ask yourself this question:

  • Without looking inside the class file, what exactly does the ChessGame need in order to execute playGame()?

It’s not at all obvious is it! My guess would be that we only really need player names, and handicap information (why do we need the player bio to play a match??). If this is the case, why do we pass all that extra information to the ChessGame constructor, if it’s never going to need it?

I can hear you answering “But it’s far more convenient to package up that information as it exists naturally – inside the Player object. It is more readable, and keeps the number of constructor parameters down!”

But this is not a valid reason because of the following:

  1. Classes should not ask for more information than they need – otherwise they become difficult and cumbersome to test
  2. Classes should make absolutely clear what their dependencies are. This is why passing around “Contexts” is a bad thing

We can make this a lot easier by using a Factory Method as a convenience:

class ChessGame {
 
    public ChessGame (String player1Name, String player2Name, 
                int player1Handicap, int player2Handicap, int timeLimit) {
 
        this.player1Name = player1Name;
        this.player2Name = player2Name;	
        //..etc
    }
 
    public static ChessGame withPlayers (Player player1, Player player2, int timeLimit) {
        return new ChessGame (
            player1.getName(), 
            player2.getName(),
            player1.getHandicap().getAbsolute(),
            player2.getHandicap().getAbsolute());
    }
 
    public void playGame() {...}
}
 
class ChessGameTest {
    @Test
    public void testChessGamePlaysForXseconds () throws Exception {
 
        new ChessGame("D. Duck", "M. Mouse", 10, 4, 10);
 
        // Assertions ....
    }
}

The second ChessGame class accepts only what it needs – it has fewer dependencies on real objects. However, we now have a nice convenience method on the object which takes our existing objects.

Why stop there? Here are some more Factory Methods which you might prove useful:

public static ChessGame fromExistingGame (ChessGame previousGame) {...}
public static ChessGame againstBot (BotFactory botFactory) {...}
public static ChessGame fromDataFile (File dataFile) {...}

 

So in conclusion – if you’re finding yourself setting up tonnes of scaffolding for a test, ask yourself whether the unit-to-be-tested is asking too much of you!

  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • DZone
  • Slashdot
  • Twitter

Painless TDD – Using Equality to Test Your Code

May 7th, 2012

… or, why Getters are a Code Smell!

A common problem arises when you need to change the underlying implementation of a class, and you want to use your existing tests to assert that the outward behaviour of this class has not changed. You may well take the following approach:

  1. Make changes to your class implementation
  2. Fix any tests that have broken
  3. Re-run the tests. Do they pass?

Can you spot a problem with this approach? When you change your tests, you cannot rely on them to validate your code anymore. The point of verifying change using Unit Tests is that they remain an invariant. If you have changed both your code and your tests, then you have no confidence that you haven’t introduced a bug in your work!

Look at the code sample below:

    @Test
    public void testTwoCorrectAnagramsAreGenerated() throws Exception{
 
        // Given : a basic anagram generator
        // When : presented with the word "sleep"
        WordList wordList = new AnagramGenerator().generateAnagrams("sleep");
 
        // Then : we get two anagrams - "sleep" and "peels"
        List words = wordList.getWords();
        assertEquals("First anagram", "sleep", words.get(0));
        assertEquals("Second anagram", "peels", words.get(1));
        assertEquals("Size", 2, words.size());
    }

This simple test is flawed:

  1. We are assuming that the implementation of WordList will always store its words in a List<String>. In fact, we are forced to expose the underlying structure of our object.
  2. The test will fail if we change the order in which the anagrams are returned. Should the order of the returned anagrams really be a concern in this situation?
  3. WordList has become a central focal point of our test, even though we are testing the AnagramGenerator
A better test would instead use the .equals() method to test correctness:
    @Test
    public void testTwoCorrectAnagramsAreGenerated() throws Exception{
 
        // Given : a basic anagram generator
        // When : presented with the word "sleep"
        WordList list = new AnagramGenerator().generateAnagrams("sleep");
 
        // Then : we get two anagrams - "sleep" and "peels"
        assertEquals("Anagram List", new WordList("sleep","peels"), list);
   }

The result is that we have a smaller test, which doesn’t poke around inside the WordList class when making assertions. The only thing we need to assume is that Object.equals(Object) has been implemented correctly (testing this can be done separately in WordListTest).

Furthermore, if we decide that ordering of results is not important, we can have WordList implement a HashSet. The .equals() method will therefore not check for ordering.

Using equality rather than introspection will ensure that your tests are less brittle and invariant to change. Happy TDDing!

 

  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • DZone
  • Slashdot
  • Twitter

Learn to Program with Poker / Code with Cards

June 11th, 2011

P1020341 I love learning new programming languages. I’ve been reading Bruce Tate’s “Seven Languages In Seven Weeks” with the hope of getting a flavour of all the different paradigms on offer. It is impossible to learn a new languages by simply reading – you have to get stuck in with the code to gain a true understanding. Mr Tate gives us the opporutunity to dive into some practice examples he has thoughtfully prepared for us. They are a good start, but i like something more involved to move onto.

And that’s where poker comes in. Texas Hold’em may or may not be your cup of tea, but it is a game to perfectly test your understanding of the languages you are writing in.

Just look at the different elements that come into play:

  • Scoring hands. This is a non-trivial task that is on the surface, quite straightforward with OO. But scoring hands is perfect for functional languages. For extra difficulty, remember – Ace is both high and low!
  • Who wins what? With varying players in the game, and varying amounts in the pot, this could get tricky!
  • Performance. Ok, so you’ve worked hard on your perfect card-scoring functions. Now we can really test how well you’ve done by asking “how many hands can we score per second?”.
  • DSLs. Perhaps the language you are using is good for developing DSLs. Could you write a DSL that mimics a hand of poker? One round? Or even an entire poker game? Something such as the following would be a start (I’m pretty sure Scala’s implicit type conversions will perform this miracle):

“AC QH 10S 2D 4C 8D AD” vs “3S 10C 3C 5H QD QS 7S”

  • AI. If you’ve played poker, you know it can be an infinitely complex game of deep strategy. But even a simple A.I. bot can give a player a good run for his money. Start with the basics (hand strength, pot odds, outs) and go from there.
  • Immutability. Can you complete your program whilst keeping it completely immutable? I don’t mean scores, chips, etc. I mean, can you avoid mutable data structures, state-ful functions, etc.

Once I’ve written a basic poker engine once, it becomes easier to use it as a comparison between languages. I have a firmer understanding of which languages perform better in which circumstances. Oh, and it’s definitely more fun than writing business applications!

  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • DZone
  • Slashdot
  • Twitter

Get Better At: IntelliJ IDEA

December 13th, 2010

IntelliJ IDEA is a wonderful piece of software.

And that’s all I’m going to say; I won’t run comparisons against other popular IDEs, because that’s a subject for another day. Today, I want to talk about sharpening your skills with IDEA.

Shortcuts

We all know that shortcuts improve our productivity. Here are the ones I find most valuable:

  • CTRL-W and CTRL-SHIFT-W: Select progressively greater / lesser levels of code
  • CTRL-ALT-V: Introduce Variable. See also Introduce Field / Constant
  • type “iter” TAB: Java 5 style for loop Live Template. See sections below for more info on this
  • ALT-LEFT and ALT-RIGHT: View previous / next tab.
  • CTRL-ALT-LEFT and CTRL-ALT-RIGHT: Back / Forward Tab (in history).
  • CTRL-N and CTRL-SHIFT-N: Find Class and Find File.
  • ALT-F12: Show class outline (press again to also show Inherited members).
  • CTRL-D: Duplicate Line.
  • F2 and SHIFT-F2: Go to next / previous error (or warning).
  • ALT-INSERT: Create new file popup.
  • CTRL-SHIFT-F: Find in path.
  • CTRL-ALT-T: Show list of Live Templates.
  • ALT-ENTER: Show Intentions (see below for more info)

Live Templates

Live Templates are snippets of code you can insert in and around pieces of code. The most common one would probably be “Surround with If”, which takes the highlighted code and surrounds it with an If statement. What’s more, it formats the code correctly so you needn’t worry about tab spacing.

Another good Live Template is the for loop generator. Type “iter” and then hit TAB. IDEA intelligently selects a list of collections you might wish to iterate over:

To create you’re own templates, I would recommend you take a look at this Jetbrains blog post describing how to create a null-check template.

Quick Lists
You can create a shortcut to open a popup of commonly used items of your choosing. Within Preferences, go to Quick Lists to define a new list, and then Key Intentions to create a shortcut for that list. As an example:

Intentions
Intentions can be used to perform common actions, or solve problems with your code. Hitting ALT-ENTER over a valid piece of code will give you common actions. Doing the same over an error will give some suggestions such as:

  • Migrate Type
  • Cast expression
  • Import unknown symbol

Below is an example of both forms of intention:

  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • DZone
  • Slashdot
  • Twitter

Using WLST to find JMX MBeans on Weblogic Application Server 10.3

December 13th, 2010

I was recently asked to retrieve a selection of JMX MBean attribute values from Weblogic Application Server, and format the data as XML to be read by Nagios. JBoss Application Server provides a nice frontend within their administration console in which to naviate the MBean hierarchy, and find the MBean names you need.

Oracle doesn’t do this when it comes to Weblogic 10.3. Instead, you can either use educated guesswork in combination with some useful documentation. Or you can use WLST – the Weblogic Scripting Tool.

Using the Weblogic Scripting Tool
The first thing to do is find the binary. This is located here:

%BEA_HOME%/common/bin/wlst.bat <-- Windows
%BEA_HOME%/common/bin/wlst.sh <-- Unix

Start the executable, and wait until you receive a prompt. There is a list of common commands you will need:


connect('username','password','host:port')
serverRuntime()
cd('beanName')
ls()

As you can see, you will be familiar with the commands if you have ever used a unix command prompt before. Be aware that we execure the commands like functions, within brackets, with a number of arguments.

Example

Welcome to WebLogic Server Administration Scripting Shell

Type help() for help on available commands

wls:/offline> connect('weblogic','weblogic','localhost:7001')
Connecting to t3://localhost:7001 with userid weblogic ...
Successfully connected to Admin Server 'devserver' that belongs to domain 'vfdomain'.

Warning: An insecure protocol was used to connect to the
server. To ensure on-the-wire security, the SSL port or
Admin port should be used instead.

wls:/vfdomain/serverConfig> serverRuntime()
Location changed to serverRuntime tree. This is a read-only tree with ServerRuntimeMBean as the root.
For more help, use help(serverRuntime)

wls:/vfdomain/serverRuntime> ls()
dr-- ApplicationRuntimes
dr-- AsyncReplicationRuntime
dr-- ClusterRuntime
dr-- ConnectorServiceRuntime
dr-- DefaultExecuteQueueRuntime
dr-- EntityCacheCumulativeRuntime
dr-- EntityCacheCurrentStateRuntime
dr-- EntityCacheHistoricalRuntime
dr-- ExecuteQueueRuntimes
dr-- JDBCServiceRuntime
dr-- JMSRuntime
dr-- JTARuntime

snip....
-r-- ActivationTime 1267615098514
-r-- AdminServer true
-r-- AdminServerHost 127.0.0.1
-r-- AdminServerListenPort 7001
-r-- AdminServerListenPortSecure false
-r-- AdministrationPort 9002
snip....

The first list of items are child MBeans. The second list are attributes.

We can navigate to our JDBC connections like so:


wls:/vfdomain/serverRuntime> cd('JDBCServiceRuntime/myserver/JDBCDataSourceRuntimeMBeans/mydatasource')
wls:/vfdomain/serverRuntime/DBCServiceRuntime/myserver/JDBCDataSourceRuntimeMBeans/mydatasource> ls()
snip...
-r-- ConnectionDelayTime 97
-r-- ConnectionsTotalCount 144
-r-- CurrCapacity 10
-r-- CurrCapacityHighCount 11
-r-- DeploymentState 2
-r-- Enabled true
-r-- FailedReserveRequestCount 0
-r-- FailuresToReconnectCount 0
-r-- HighestNumAvailable 12
-r-- HighestNumUnavailable 0
-r-- LastTask null
-r-- LeakedConnectionCount 0
-r-- ModuleId mydatasource
-r-- Name mydatasource
-r-- NumAvailable 10
-r-- NumUnavailable 0
-r-- PrepStmtCacheAccessCount 7836
-r-- PrepStmtCacheAddCount 3808
-r-- PrepStmtCacheCurrentSize 99
snip...

  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • DZone
  • Slashdot
  • Twitter