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.
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.
Use return null . Void can't be instantiated and is merely a placeholder for the Class<T> type of void .
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With