A canonical Repository test

how-to
Mar 8, 201313 mins

There are only so many ways to test that your persistence layer is implemented correctly or that you’re using an ORM correctly. Here’s my canonical tests for a repository (Java-version):

<span style="color: #000000; font-weight: bold;">import</span> <span style="color: #006699;">static</span> org.<span style="color: #006633;">fest</span>.<span style="color: #006633;">assertions</span>.<span style="color: #006633;">api</span>.<span style="color: #006633;">Assertions</span>.<span style="color: #339933;">*;</span>
 
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> PersonRepositoryTest <span style="color: #009900;">{</span>
    <span style="color: #000000; font-weight: bold;">private</span> PersonRepository repository<span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// TODO < == you must initialize this</span>
 
    @Test
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> shouldSaveAllProperties<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
        Person person <span style="color: #339933;">=</span> randomPerson<span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
        repository.<span style="color: #006633;">save</span><span style="color: #009900;">(</span>person<span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// TODO: Make sure your repository flushes!</span>
        assertThat<span style="color: #009900;">(</span>repository.<span style="color: #006633;">find</span><span style="color: #009900;">(</span>person.<span style="color: #006633;">getId</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #009900;">)</span>
            .<span style="color: #006633;">isNotSameAs</span><span style="color: #009900;">(</span>person<span style="color: #009900;">)</span>
            .<span style="color: #006633;">isEqualTo</span><span style="color: #009900;">(</span>person<span style="color: #009900;">)</span>
            .<span style="color: #006633;">isEqualsToByComparingFields</span><span style="color: #009900;">(</span>person<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">}</span>
 
    @Test
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> shouldFindByCaseInsensitiveSubstringOfName<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
        Person matching <span style="color: #339933;">=</span> randomPerson<span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
        Person nonMatching <span style="color: #339933;">=</span> randomPerson<span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
        matching.<span style="color: #006633;">setName</span><span style="color: #009900;">(</span><span style="color: #0000ff;">"A. Matching Person"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
        nonMatching.<span style="color: #006633;">setName</span><span style="color: #009900;">(</span><span style="color: #0000ff;">"A. Random Person"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
        repository.<span style="color: #006633;">save</span><span style="color: #009900;">(</span>matching<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
        repository.<span style="color: #006633;">save</span><span style="color: #009900;">(</span>nonMatching<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
        assertThat<span style="color: #009900;">(</span>repository.<span style="color: #006633;">findByNameLike</span><span style="color: #009900;">(</span><span style="color: #0000ff;">"MATCH"</span><span style="color: #009900;">)</span><span style="color: #009900;">)</span>
            .<span style="color: #006633;">contains</span><span style="color: #009900;">(</span>matching<span style="color: #009900;">)</span>
            .<span style="color: #006633;">doesNotContain</span><span style="color: #009900;">(</span>nonMatching<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">}</span>
<span style="color: #009900;">}</span>

Very simple. The randomPerson test helper generates actually random people:

<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> PersonTest <span style="color: #009900;">{</span>
    <span style="color: #666666; font-style: italic;">// ....</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> Person randomPerson<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
        Person person <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> Pesron<span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
        person.<span style="color: #006633;">setName</span><span style="color: #009900;">(</span>randomName<span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
        <span style="color: #666666; font-style: italic;">// TODO Initialize all properties</span>
        <span style="color: #000000; font-weight: bold;">return</span> person<span style="color: #339933;">;</span>
    <span style="color: #009900;">}</span>
 
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #003399;">String</span> randomName<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
        <span style="color: #000000; font-weight: bold;">return</span> RandomData.<span style="color: #006633;">randomWord</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #339933;">+</span> <span style="color: #0000ff;">" "</span> <span style="color: #339933;">+</span> RandomData.<span style="color: #006633;">randomWord</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #339933;">+</span> <span style="color: #0000ff;">"son"</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">}</span>
<span style="color: #009900;">}</span>
 
 
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> RandomData <span style="color: #009900;">{</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #003399;">String</span> randomString<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
        <span style="color: #000000; font-weight: bold;">return</span> random<span style="color: #009900;">(</span><span style="color: #0000ff;">"foo"</span>, <span style="color: #0000ff;">"bar"</span>, <span style="color: #0000ff;">"baz"</span>, <span style="color: #0000ff;">"qux"</span>, <span style="color: #0000ff;">"quux"</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// TODO: Add more!</span>
    <span style="color: #009900;">}</span>
 
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #339933;"><</span>T<span style="color: #339933;">></span> T random<span style="color: #009900;">(</span>T... <span style="color: #006633;">options</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
        <span style="color: #000000; font-weight: bold;">return</span> options<span style="color: #009900;">[</span>random<span style="color: #009900;">(</span>options.<span style="color: #006633;">length</span><span style="color: #009900;">)</span><span style="color: #009900;">]</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">}</span>
 
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #000066; font-weight: bold;">int</span> random<span style="color: #009900;">(</span><span style="color: #000066; font-weight: bold;">int</span> max<span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
        <span style="color: #000000; font-weight: bold;">return</span> random.<span style="color: #006633;">nextInt</span><span style="color: #009900;">(</span>max<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">}</span>
 
    <span style="color: #000000; font-weight: bold;">private</span> <span style="color: #000000; font-weight: bold;">static</span> <span style="color: #003399;">Random</span> random <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Random</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
<span style="color: #009900;">}</span>

If your data has relationships with other entities, you may want to include those as well:

<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> OrderRepositoryTest <span style="color: #009900;">{</span>
    <span style="color: #000000; font-weight: bold;">private</span> OrderRepository repository<span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// TODO < == you must initialize this</span>
    <span style="color: #000000; font-weight: bold;">private</span> PersonRepository personRepository<span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// TODO <== you must initialize this</span>
 
    <span style="color: #000000; font-weight: bold;">private</span> Person person <span style="color: #339933;">=</span> PersonTest.<span style="color: #006633;">randomPerson</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #339933;">;</span>
 
    @Before
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> insertData<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
        personRepository.<span style="color: #006633;">save</span><span style="color: #009900;">(</span>person<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">}</span>
 
    @Test
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> shouldSaveAllProperties<span style="color: #009900;">(</span><span style="color: #009900;">)</span> <span style="color: #009900;">{</span>
        Order order <span style="color: #339933;">=</span> randomOrder<span style="color: #009900;">(</span>person<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
        repository.<span style="color: #006633;">save</span><span style="color: #009900;">(</span>order<span style="color: #009900;">)</span><span style="color: #339933;">;</span> <span style="color: #666666; font-style: italic;">// TODO: Make sure your repository flushes!</span>
        assertThat<span style="color: #009900;">(</span>repository.<span style="color: #006633;">find</span><span style="color: #009900;">(</span>order.<span style="color: #006633;">getId</span><span style="color: #009900;">(</span><span style="color: #009900;">)</span><span style="color: #009900;">)</span>
            .<span style="color: #006633;">isNotSameAs</span><span style="color: #009900;">(</span>order<span style="color: #009900;">)</span>
            .<span style="color: #006633;">isEqualTo</span><span style="color: #009900;">(</span>order<span style="color: #009900;">)</span>
            .<span style="color: #006633;">isEqualsToByComparingFields</span><span style="color: #009900;">(</span>order<span style="color: #009900;">)</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">}</span>

A simple and easy way to simplify your Repository testing.

(The tests use FEST assert 2 for the syntax. Look at FluentAssertions for a similar API in .NET)

(Yes, this is what some people would call an integration test. Personally, I can’t be bothered with this sort of classifications)