Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to prevent Geb from returning null from void methods?

Tags:

groovy

spock

geb

In a Spock Specification any line in expect: or then: block is evaluated and asserted as boolean, unless it has signature with return type void.

I've noticed that there is something odd going on for methods declared as void on any class inheriting from Navigator (for example Page or Module classes).

Let say we have such example:

class NavigationSpec extends GebSpec {

    def 'Collections page has a right header'() {

        when:
            to CollectionsPage

        then:
            hasHeaderText('Collections')
    }
}

The hasHeaderText() method is defined within CollectionsPage class as follows:

class CollectionsPage extends Page {

    static url = 'movies/collections'

    void hasHeaderText(String expectedText) {
        assert true
    }
}

On purpose I'm just asserting true over there so it should never fail. Even though it fails with an error:

Condition not satisfied:

hasHeaderText('Collections')
|
null

How and why a void method call result is evaluated as null?

I know how to 'fix it'. It's enough to declare the method return type as boolean and return true. This is ugly though as following all the asserts otherwise unnecessary return true has to be added like:

boolean hasHeaderText(String expectedText) {
    assert header.text() == expectedText
    return true
}

This causes only noise though. Is there any way to prevent Geb from returning null from void methods?

I'm, of course, aware that this specific case could go like:

boolean hasHeaderText(String expectedText) {
    header.text() == expectedText`
}

This doesn't explain the oddity of lost void return type, not to mention we loose meaningful assert failure message with such approach.

like image 920
topr Avatar asked Apr 11 '16 12:04

topr


People also ask

Do void methods return null?

A void return type has been introduced. Functions declared with void as their return type must either omit their return statement altogether, or use an empty return statement. null is not a valid return value for a void function.

Which return type is used to return to nothing for void?

Use return null . Void can't be instantiated and is merely a placeholder for the Class<T> type of void .

Is return on void good practice?

1) A Void Function Can Return: We can simply write a return statement in a void fun(). In fact, it is considered a good practice (for readability of code) to write a return; statement to indicate the end of the function.

What should I return instead of null?

Several alternatives for returning null values include using null object reference types, a null object pattern, and a result type as the return type. Therefore, the recommendation is to return an empty value instead of a null to keep the code clean and error-free.


1 Answers

It's part of the Groovy language that every method returns a value. This allows any method to be used in expressions or as lambdas.

All methods that are declared void return null.

If you don't explicitly have any return statement, the result of the last expression in your method is returned.

You can look at the bytecode... even if you declare a return type, you don't actually need to return anything as Groovy will, by default, return null:

// returns null
String callMe() { }

static void main(args) {
    def x = callMe()
    assert x == null
    println "OK!"
}

Because Spock will assert anything in the then block which is not a simple assignment, you need to avoid doing anything other than boolean assertions in the then block. Even assigning a variable, though allowed, should be avoided... It's hard to keep tests clean and clear, and by adhering to these guidelines will really work for you in the long run, not against you.

So, the correct way to write the assertion you want is to make your method return a boolean:

boolean hasHeaderText(String expectedText) {
    header.text() == expectedText
}

And use it in the then block:

then: 'The header has the expected text #expectedText'
hasHeaderText expectedText

Looks pretty good if you ask me.

EDIT

I've noticed that Groovy/Spock actually will not assert the result of a normal void method even in the then block... What's probably going on here is that you don't have a normal void method, you seem to be calling a dynamic method of CollectionsPage (I guess that's Geb's magic in play), which means that, probably, the Spock AST Transformer does not have the opportunity to check the signature of the method you're calling, so it correctly assumes it must assert the result... at least that's what it looks like.

like image 133
Renato Avatar answered Sep 19 '22 00:09

Renato