Unit testing tricks: Look ma, no setters!

how-to
Jun 14, 20094 mins

Here’s a neat trick if you want set an object in a specific state in a unit test, but you don’t want to violate encapsulation:

    @Test
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> withdrawShouldReduceBalance<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
        Account account <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Account<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span><span style="color: #009900;">{</span>
            <span style="color: #000000; font-weight: bold;">super</span>.<span style="color: #006633;">balance</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">100</span>;
        <span style="color: #009900;">}</span><span style="color: #009900;">}</span>;
        account.<span style="color: #006633;">withdraw</span><span style="color: #009900;">(</span><span style="color: #cc66cc;">10</span><span style="color: #009900;">)</span>;
        assertEquals<span style="color: #009900;">(</span><span style="color: #cc66cc;">90</span>, account.<span style="color: #006633;">getBalance</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #009900;">)</span>;
    <span style="color: #009900;">}</span>
 
    @Test<span style="color: #009900;">(</span>expected<span style="color: #339933;">=</span><span style="color: #003399;">IllegalStateException</span>.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">)</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> overdraftShouldThrow<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
        Account account <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Account<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span><span style="color: #009900;">{</span>
            <span style="color: #000000; font-weight: bold;">super</span>.<span style="color: #006633;">balance</span> <span style="color: #339933;">=</span> <span style="color: #cc66cc;">5</span>;
        <span style="color: #009900;">}</span><span style="color: #009900;">}</span>;
        account.<span style="color: #006633;">withdraw</span><span style="color: #009900;">(</span><span style="color: #cc66cc;">10</span><span style="color: #009900;">)</span>;
    <span style="color: #009900;">}</span>

This seemingly magic code lets me have a protected (but sadly not private) field Account#balance. I can set this field in each individual test method.

It looks very magic, so it deserves a brief explanation:

  1. The first set of curlies create an anonymous subclass of Account. That is: new Account() {}.
  2. The second set of curlies creates an initializer block, that is: a block of code that is added to the constructor.
  3. So in effect: Each test method creates a subclass of Account and modifies the account field in the constructor. This is why Account#balance must be protected instead of private.

This trick (and it is a trick) lets me set up the object under test to any state I want, without needing a special constructor and without breaking encapsulation by adding a setter. However, I’m required to make the fields I want to initialize protected. Additionally, each test method creates one or more new classes. This could potentially affect performance and/or memory use during compilation and/or running of tests. I’ve only used the trick at a small scale, so I don’t know if I’ll run into these issues in the future.

So, what do you think: How big of a “WTF” is this code?