This page looks best with JavaScript enabled

Places where you REALLY NEED to use 'assert' keyword in Spock assertions

 ·   ·  ☕ 5 min read

Make sure you know all the places where putting the ‘assert’ keyword in Spock is necessary to avoid false sense of security and tests which - effectively - do nothing.

TODO

Introduction

Spock greatly simplifies test creation. One of the improvements is an ability to skip the assert keyword in the verification block (then or expect). It is very convenient, but Spock newcomers (and based on my code testing training also even more experienced developers) might not be aware that under some circumstances that keyword is required, making - as a result - that particular test useless. After lecture of this blog post you will know the places (situations) where the assert keyboard is mandatory.

Let’s start from the beginning.

Power assertions

Power assertions is an advanced assertion mechanism which renders the failed assertion in a very meaningful way. For example:

assert (2 + 3) * 4 != (2 * 4) + (3 * 4)

results in:

Assertion failed:

assert (2 + 3) * 4 != (2 * 4) + (3 * 4)
          |    |   |     |    |    |
          5    20  false 8    20   12

This is a great step forward over the classic assertEquals() assertion with just Assertion failed in JUnit.

What is nice, it works also for objects and method calls:

Assertion failed: 

assert ann.name == bob.name && ann.age == bob.age
       |   |    |  |   |    |
       |   Ann  |  |   Bob  false
       |        |  Person(name:Bob, age:7)
       |        false
       Person(name:Ann, age:4)

Power assertions have been developed initially for Spock, but later on they were backported to Groovy 1.7 (2009). Currently, they are one of the killer features of Groovy in the context of testing (in general, not only with Spock).

Optional ‘assert’

As I already mentioned in the introduction, Spock using the Groovy magic (primarily AST transformations and operator overloading) generates and automatically handles different aspect of tests to make its creation as simple as possible. Among others, it is visible in exception testing - a hidden try..catch around the when block or implicit method arguments in parameterized tests.

Another case for simplification in an optional assert keyword with assertions. For example:

    ...
expect:
    assert numberOfItems == 2

can be simplified to just:

    ...
expect:
    numberOfItems == 2

The assert keyword is automatically added by the Spock AST transformation in the then or expect blocks, if there is a boolean value, but also any non-void statement which can be evaluated with The Groovy Truth .

This opens different possibilities:

    ... 
when:
    List<Invoiced> overdueInvoices = userAccount.getOverdueIncoives()
then:
    overdueInvoices   //collection cannot be null or empty to not to fail

Under the hood, the Spock AST transformation detects all those places to enhance them with assert, but there are some limitations.

Required ‘assert’

There are places (situations) where assert cannot be omitted. It is especially crucial to know them as there is no error displayed. The assertions just do not work which makes them useless. Or event worse, it gives a false sense of security - those tests do not test anything.

Guard assertion

The first case is so-called guard assertion. Occasionally, mostly in integration/acceptance testing there is a need to check the initial state (e.g. number of records in a database to ensure than some previously added new - badly written - test did not break our test data).

Spock cares only about then and expect blocks in the context of the implicit assert. The assert keyword is not automatically added in the given block and has to be placed manually.

given:
    List<Invoice> initialInvoices = legacyRepository.getUserInvoices(USER_ID)  
    assert initialInvoices.size() == 0  //'assert' is mandatory - 'initialInvoices.size() == 0' does nothing!
when:
    issueInvoice(...)
then:
    legacyRepository.getUserInvoices(USER_ID).size() == 1   //'assert' is not needed in 'then' 

Assertion in method execution

The another situation refers to the then (or expect) block. Sometimes there is a set of assertions that is used in more than one tests. It might be handy to extract them to a separate method (placed locally in the test class, in a super class, or in a trait):

    when:
        ...
    then:
        assertCompatibilityWithArticle17OfEUDirective(socialMediaSubmission)
}

private void assertCompatibilityWithArticle17OfEUDirective(SocialMediaSubmission submission) {
    assert submission.field1 == ...  //'assert' is mandatory 
    assert submission.field2 == ...
}

For Spock, method call is treated as a regular value to be evaluated (if method is non-void). Therefore, if a method returns false or 0 or an empty collection the test fails. Otherwise, also if a method has the void return type, the test passes.

It is requires to care about the assertions manually, but placing the assert keyword explicitly withing the method.

Assertion in Closure execution

A similar class of problems poses assertions within closures. They might be not so often used as in methods, but it makes them even more at risk of incorrect usage.

    ...
expect:
    GParsPool.withPool {
        ["1"].eachParallel CorrelationIdUpdater.wrapClosureWithId {
            assert it == "1"    //mandatory "assert"
        }
    }

With Groovy 3 (and Spock 2.0-M2+ ) the same applies to assertions in lambda expressions.

Other cases

Quoting the Spock documentation :

Conditions are an essential ingredient of then blocks and expect blocks. Except for calls to void methods and expressions classified as interactions, all top-level expressions in these blocks are implicitly treated as conditions.

So, in addition to the 3 aforementioned cases, anything not “top-level” (or not placed in the then and expect blocks) should bring our attention. That includes - less popular - conditional statements (if/else), loops, and the catch blocks.

Updated 2021-12-26. Added the “Other cases” section, based on a constructive comment by Hari Krishna Dara .

Summary

Spock and Groovy (as every tool or language) can be used in more or less “messy way”. Groovy being a very flexible and optionally dynamic language makes it even easier. “With great power comes great responsibility”, a proverb popularized by the Spider-Man franchise, can be applied also to Spock. Users should be aware of the limitations and corner cases to avoid mistakes.

Btw, in the context of assertions those are corner cases where assertion(-like) expression is just ignored, which is much worse than just an error. However, it is not the only place. A few years ago I made a 50-minutes long presentations just about “Interesting nooks and crannies of Spock” (slides and videos ). And definitely I didn’t exhausted a topic :-).

Lead photo based on unofficial Spock logo proposal from 2014 by Søren Berg Glasius and work safety signs by Clker-Free-Vector-Images, published in Pixabay.
Share on

Marcin Zajączkowski
WRITTEN BY
Marcin Zajączkowski
Software Craftsman & Software Architect
An experienced architect aiming for high quality solutions. Very engaged in evangelising Software Craftsmanship, Clean Code and Test-Driven Development as a conference speaker and a trainer. A specialist in Continuous Delivery and Continuous Inspection of Code Quality. An enthusiast of Reactive Systems and broadly defined concurrency.

Besides, open source author and contributor, a proud Linux user.


Don't want to use the Utterance bot? Comments can be also placed directly on GitHub.
What's on this Page