I have a Groovy class which receives an argument to its constructor and checks it with a Power Assert statement like so:
public MyClass(Map args) {
assert args.firstArg
}
Normally the value of args.firstArg
is an instance of another Groovy class within my project. When I use a real instance of this class, the assertion passes. However when I use the Spock Mocking framework to pass in a mocked instance of the method, the assertion fails:
Assertion failed:
assert args.firstArg
| |
| Mock for type 'OtherClass' named 'mockOtherClass'
['firstArg':Mock for type 'OtherClass' named 'mockOtherClass']
However, when I change the code to
assert args.firstArg != null
then my code works.
Up until now, I had naively thought that
assert args.firstArg
was just shorthand for doing a null check.
Based on what I have observed passing in mocked class instances this is not the case, and I was wondering if someone can help me to understand what the difference is.
@hayfreed: Actually, I do not like to speculate, so please next time (or this time, in case my guess is wrong) provide more than just a set of incoherent code snippets when asking questions on StackOverflow. Ideally, provide an MCVE (please read!).
Let us create an MCVE first, shall we?
package de.scrum_master.stackoverflow.q62543765
class OtherClass {}
package de.scrum_master.stackoverflow.q62543765
class MyClass {
MyClass(Map args) {
assert args.firstArg
}
}
package de.scrum_master.stackoverflow.q62543765
import spock.lang.Specification
class MyClassTest extends Specification {
def "do not use mock"() {
when:
new MyClass([firstArg: new OtherClass(), secondArg: "foo"])
then:
noExceptionThrown()
when:
new MyClass([firstArg: null, secondArg: "foo"])
then:
thrown AssertionError
when:
new MyClass([secondArg: "foo"])
then:
thrown AssertionError
}
def "use mock"() {
when:
new MyClass([firstArg: Mock(OtherClass), secondArg: "foo"])
then:
noExceptionThrown()
}
}
This test passes. But what if we change OtherClass
to be a collection type instead?
package de.scrum_master.stackoverflow.q62543765
class OtherClass extends ArrayList<String> {}
The test fails in the feature method not using the mock:
Expected no exception to be thrown, but got 'org.codehaus.groovy.runtime.powerassert.PowerAssertionError'
at spock.lang.Specification.noExceptionThrown(Specification.java:118)
at de.scrum_master.stackoverflow.q62543765.MyClassTest.do not use mock(MyClassTest.groovy:10)
Caused by: Assertion failed:
assert args.firstArg
| |
| []
['firstArg':[], 'secondArg':'foo']
at de.scrum_master.stackoverflow.q62543765.MyClass.<init>(MyClass.groovy:5)
at de.scrum_master.stackoverflow.q62543765.MyClassTest.do not use mock(MyClassTest.groovy:8)
So you see that Groovy truth is more than a null check. E.g. collection types yield false
for assertions also if the collection is empty.
But back to your problem. How could the test for the mock fail? My best guess, not having seen the code for your OtherClass
, is that the class implements an asBoolean
method, as also described in the manual section about Groovy truth:
package de.scrum_master.stackoverflow.q62543765
class OtherClass {
boolean asBoolean(){
true
}
}
Now the test failure looks much like yours:
Expected no exception to be thrown, but got 'org.codehaus.groovy.runtime.powerassert.PowerAssertionError'
at spock.lang.Specification.noExceptionThrown(Specification.java:118)
at de.scrum_master.stackoverflow.q62543765.MyClassTest.use mock(MyClassTest.groovy:28)
Caused by: Assertion failed:
assert args.firstArg
| |
| Mock for type 'OtherClass'
['firstArg':Mock for type 'OtherClass', 'secondArg':'foo']
at de.scrum_master.stackoverflow.q62543765.MyClass.<init>(MyClass.groovy:5)
at de.scrum_master.stackoverflow.q62543765.MyClassTest.use mock(MyClassTest.groovy:26)
How would you fix that? Just stub the asBoolean
method to return true
:
def "use mock"() {
given:
def otherClass = Mock(OtherClass) {
asBoolean() >> true
}
when:
new MyClass([firstArg: otherClass, secondArg: "foo"])
then:
noExceptionThrown()
}