How to get Spock to match in Reactor similar to Mockito? - groovy

I am trying to test a class that will call another web service to fetch data if a null value is provided. My JUnit + Mockito test works great, but I cannot get my Spock test to match in the then: block. The error returned during the Spock test is:
Suppressed: java.lang.NullPointerException: Cannot invoke method map() on null object
Which is because my mocked method is not matching, and therefore returns null.
Spock test (not working)
class MySpec extends Specfication {
def mockCollaboratingService = Mock(CollaboratingService)
def service = new MyService(collaboratingService: mockCollaboratingService)
def "should call another service if the provided start value equals null"() {
given:
def id = 123
def startDate = null
when: "the service is called"
def result = service.getTransactions(id, startDate)
then:
1 * mockCollaboratingService.getData(id) >> Mono.just(new SomeMockResponse(key: "123"))
StepVerifier
.create(result)
.consumeNextWith({
// assertions here
})
.verifyComplete()
}
}
JUnit + Mockito (working)
class AnotherSpec {
def mockCollaboratingService = Mockito.mock(MockCollaboratingService)
def service = new MyService(collaboratingService: mockCollaboratingService)
#Test
#DisplayName("should call the statement service if the given start date is null")
void shouldCallStatementServiceIfStartDateEqualsNull() {
def id = 123
def startDate = null
// and some fake data returned from the api
Mockito.when(mockCollaboratingService.getData(id)).thenReturn(Mono.just(new SomeMockResponse(key: "123")))
//when
def result = service.getTransactions(id, null)
//then
StepVerifier
.create(result)
.consumeNextWith({
Mockito.verify(mockStatementService, Mockito.times(1)).getLastStatement(enterpriseToken)
assert it.transactionId == 123
})
.verifyComplete()
}
}

Spock handles mocking differently than mockito, have a look at combining mocking and stubbing. Furthermore, all interactions must be finished before the then block, as Spock verifies them as first thing. With reactor, it is actually StepVerifier that is executing the code. The line def result = service.getTransactions(id, startDate) only creates a cold Mono/Flux, but doesn't to anything.
So, you have to reorder your tests slightly.
class MySpec extends Specfication {
def mockCollaboratingService = Mock(CollaboratingService)
def service = new MyService(collaboratingService: mockCollaboratingService)
def "should call another service if the provided start value equals null"() {
given:
def id = 123
def startDate = null
when: "the service is called"
def result = service.getTransactions(id, startDate)
and: "code is executed"
StepVerifier
.create(result)
.consumeNextWith({
// no explicit mock assertions necessary
assert it.transactionId == 123
})
.verifyComplete()
then:
1 * mockCollaboratingService.getData(id) >> Mono.just(new SomeMockResponse(key: "123"))
}
}

Related

In Groovy/Spock assert call methods are not executed

In Groovy Unit Test with Spock the following task is quite common:
assert myResult == calculateExpectedResult() (With or without the assert keyword.)
The groovy assert prints out lots of infomation on what is going on here and why my assertion failed. But when the compared objects are very complex and deep it can be tricky go get the concrete property that failed the test.
For this I found the Javers Framework that does an excellent Job comparing the objects and producing an exact diff. I created a trait to do this:
trait DiffTrait {
Javers javers = JaversBuilder.javers().build()
String diff(result, expected) {
Diff diff = javers.compare(result, expected);
def valueChanges = diff.getChangesByType(ValueChange)
String message = ""
valueChanges.each { message += "\n$it.propertyName = $it.left instead of expected: $it.right" }
return message
}
}
Now I can use it in my Unit Tests like this:
def expected = calculateExpectedResult()
assert myResult == expected, diff(myResult, expected)
This way I get a nicely printed list of differences.
But this is kind of verbose because I have to specify the values two times.
So I have changed the trait like this:
trait DiffTrait {
Javers javers = JaversBuilder.javers().build()
def result
def expected
String diff(result, expected) {
Diff diff = javers.compare(result, expected);
def valueChanges = diff.getChangesByType(ValueChange)
String message = ""
valueChanges.each { message += "\n$it.propertyName = $it.left instead of expected: $it.right" }
return message
}
String diff() {
diff(result, expected)
}
def result(result) {
this.result = result
return result
}
def expected(expected) {
this.expected = expected
return expected
}
}
The idea was to use it like this:
def result = callTheSystemToProduceTheRealResult()
def expected = calculateExpectedResult()
assert result(myResult) == expected(expected), diff()
But surprisingly this does not work! The two attributes are null and the diff Method fails with a NotNull-Exception. If I debug this code the expected/result methods are never called!
If I rewrite the code like this
def result = result(callTheSystemToProduceTheRealResult())
def expected = expected(calculateExpectedResult())
assert myResult == expected, diff()
everything works as expected. The methods get called correctly and the attributes are set.
My question is: Why can't I call these methods in the assert statement? What is the difference from the Groovy/Spock perspective of these two code fragements?
Here is a gist containing all the code as running example.
It is quite easy to explain. Assertion message is evaluated before the assertion itself. The following piece of code works perfectly, however it displays static diff message:
import org.javers.core.Javers
import org.javers.core.JaversBuilder
import org.javers.core.diff.Diff
import org.javers.core.diff.changetype.ValueChange
import spock.lang.Specification
class LolSpec extends Specification implements DiffTrait {
def 'lol'() {
expect:
def whatIGot = new Lol(l: 'a')
def whatIExpected = new Lol(l: 'b')
assert result(whatIGot) == expected(whatIExpected), 'diff'
}
}
trait DiffTrait {
Javers javers = JaversBuilder.javers().build()
def result
def expected
String diff() {
diff(result, expected)
}
String diff(result, expected) {
Diff diff = javers.compare(result, expected);
def valueChanges = diff.getChangesByType(ValueChange)
String message = ""
valueChanges.each { message += "\n$it.propertyName = $it.left instead of expected: $it.right" }
return message
}
def result(result) {
this.result = result
return result
}
def expected(expected) {
this.expected = expected
return expected
}
}
class Lol {
String l
}
You need to pass the arguments twice or change the implementation, e.g.:
import groovy.transform.EqualsAndHashCode
import org.javers.core.Javers
import org.javers.core.JaversBuilder
import org.javers.core.diff.changetype.ValueChange
import spock.lang.Specification
class LolSpec extends Specification {
def 'lol'() {
expect:
def whatIGot = new Lol(l: 'a')
def whatIExpected = new Lol(l: 'b')
def diff = new Diff(result: whatIGot, expected: whatIExpected)
assert diff.check(), diff.message()
}
}
class Diff {
Javers javers = JaversBuilder.javers().build()
def result
def expected
String message() {
def diff = javers.compare(result, expected);
def valueChanges = diff.getChangesByType(ValueChange)
String message = ""
valueChanges.each { message += "\n$it.propertyName = $it.left instead of expected: $it.right" }
return message
}
boolean check() {
result.equals(expected)
}
}
#EqualsAndHashCode
class Lol {
String l
}

How to use IgnoreIf in Spock, when I check the variable?

I need to skip some functions in the program, but it should depend on a variable defined in the same program. How can I do it?
def skip = true
#IgnoreIf({ skip })
def "some function" () {
..
}
Another way to do this is by using spock's configuration file to include/exclude tests or base classes.
First you create your own annotations and place on your tests.
You then write a Spock configuration file.
When you run your tests you can set the spock.configuration property to the configuration file of your choice.
This way you can include/exclude the tests and base classes you want.
Example of spock configuration file:
runner {
println "Run only tests"
exclude envA
}
Your test:
#envA
def "some function" () {
..
}
You can then run :
./gradlew test -Pspock.configuration=mySpockConfig.groovy
Here is a github example
You can do it by accessing skip field in a static context:
import spock.lang.IgnoreIf
import spock.lang.Specification
class IgnoreIfSpec extends Specification {
static boolean skip = true
#IgnoreIf({ IgnoreIfSpec.skip })
def "should not execute this test if `IgnoreIfSepc.skip` is set to TRUE"() {
when:
def res = 1 + 1
then:
res == 2
}
def "should execute this test every time"() {
when:
def res = 1 + 1
then:
res == 2
}
}
Otherwise closure passed to #IgnoreIf() tries to find skip field inside the closure and it fails.
If the variable needs to be computed first and then the decision for test ignoring needs to be taken on the basis of computation, we can use static block and static variable
import spock.lang.IgnoreIf
import spock.lang.Specification
class IgnoreIfSpec extends Specification {
static final boolean skip
static {
//some code for computation
if("some condition")
skip = true
else
skip = false
}
#IgnoreIf({ IgnoreIfSpec.skip })
def "should not execute this test if `IgnoreIfSepc.skip` is set to TRUE"() {
when:
def res = 1 + 1
then:
res == 2
}
def "should execute this test every time"() {
when:
def res = 1 + 1
then:
res == 2
}
}
Another way is:
def skip = true
#IgnoreIf({ instance.skip })
def "some function" () {
..
}
Documentation
instance
The specification instance, if instance fields, shared
fields, or instance methods are needed. If this property is used, the
whole annotated element cannot be skipped up-front without executing
fixtures, data providers and similar. Instead, the whole workflow is
followed up to the feature method invocation, where then the closure
is checked, and it is decided whether to abort the specific iteration
or not.
Then you could do something like:
abstract class BaseTest extends Specification {
boolean skip = false
#IgnoreIf({ instance.skip })
def "some function" () { .. }
}
SubSpecification:
class GoodTest extends BaseTest {
}
class SkipTest extends BaseTest {
boolean skip = true
}
In this case, skip is a property, but it can be a method.

Getting an error with Groovy StubFor when I try and set property value

I have a dynamic AORule class that has a embedded DyanmicRule class instance as a delegate like this, and method on AORule that invokes an action on rule which tests to see if a dynamicExecution closure has been set before calling it:
#Component
#Scope("prototype")
#ActiveObject
#Slf4j
#EqualsAndHashCode
class AORule implements org.easyrules.api.Rule {
//setup delegate dynamicRule and make it a part of this ActiveObject
#Delegate DynamicRule rule
AORule (name, description=null) {
rule = new DynamicRule (name, description ?: "Basic Active Object Rule")
}
AORule () {
rule = new DynamicRule ()
}
....rest of class with a method like this
#ActiveMethod
void active_execute () {
//rule.execute()
if (rule.dynamicExecution != null) {
log.debug "activeExec : running dynamicExecution closure "
rule.dynamicExecute() //should call closure, where this is defined
}
else {
log.debug "activeExec : running std Execution action "
rule.execute()
}
} ....
where the top of the DynamicRule class looks like this:
#InheritConstructors
#Component
#Slf4j //use Groovy AST to get logger
#EqualsAndHashCode
class DynamicRule extends BasicRule implements org.easyrules.api.Rule {
Closure dynamicEvaluation = null
Closure dynamicExecution = null
....
I then try and define a simple Spock test for this and Stub the DynamicRule like so
def "set execution closure directly when doing an execute action " () {
given:"setup of stub for testing "
def mockres
def stub = new StubFor (DynamicRule)
stub.demand.dynamicExecute { mockres = "did nothing" }
stub.demand.getDynamicExecution = {true} // pretend this has been set
when : "execution passing closure value at same time "
//have to run new, actions etc in scope of class stub
stub.use {
def rule = new AORule ()
rule.execute()
}
then : "test execute closure ran as expected "
mockres == "did nothing"
}
In this test - tried to set up the Stub demand for getDynamicExecution property (a closure) to return true, and another demand to stub the method dynamicExecution to set the def mockres result. I then assert that's some value
However this gives me an error like this:
groovy.lang.MissingPropertyException: No such property: getDynamicExecution for class: groovy.mock.interceptor.Demand
at org.easyrules.spring.AORuleSpecTest.set execution closure directly when doing an execute action (AORuleSpecTest.groovy:91)
How do I set the expected result of a mocked property access in a class. I thought setting the the Stub demand expectation for getPropertyName = {some value} would do the trick. What am I doing wrong?
Post Script
I tried to setup a dumbed down version of testing approach I have used like this
class DummyStubSpecTest extends Specification {
def "test z stub " () {
def res
given :
def zstub = new StubFor (Zthing.class)
zstub.demand.execute {res = "hello"}
zstub.demand.getVar {false}
when :
zstub.use {
def a = new Athing()
a.z.execute()
}
then :
res == "hello"
}
def "test Athing stub " () {
def res
given :
def astub = new StubFor (Athing.class)
astub.demand.doit {res = "hello"}
when :
astub.use {
def a = new Athing ()
a.doit()
}
then :
res == "hello"
}
}
and a Spock test like this:
def "test z stub " () {
def res
given :
def zstub = new StubFor (Zthing.class)
zstub.demand.execute {res = "hello"}
zstub.demand.getVar {false}
when :
zstub.use {
def a = new Athing()
a.z.execute()
}
then :
res == "hello"
}
and this does work - so I'm not sure what I am doing wrong in previous example.
Second postscript
One suggestion was that I should use GroovyMock to run the test with, so I tried this
def "set execution closure using GroovyMock to Stub to execute action " () {
given:"setup of stub for testing "
def mockres
GroovyMock (DynamicRule, global:true)
DynamicRule.dynamicExecute() >> {mockres = "did nothing"}
when : "execution passing closure value at same time "
//have to run new, actions etc in scope of class stub
def rule = new AORule ()
rule.execute()
then : "test execute closure ran as expected "
mockres == "did nothing"
}
However when I run this the assertion fails again - mockres is not being set, when the execute() triggers the internal DynamicRule.dynamicExecute() method on my mocked object.
Third Postcript
I have tried again - first a 'dummy pair of classes and dummy test to try groovyMocks - and this works. Here are my eponymous Athing and Zthing
//define subject under test
class Athing {
def z = new Zthing()
def res
def doit() {
z.greet()
res = z.execute()
}
}
//dependency to be stubbed
class Zthing {
def var = true
def execute() {if (var) println "its true" else println "its false"; var}
def greet() { println "hello"}
}
here is the test i defined
class DummyStubSpecTest extends Specification {
def "test z with GroovyMock " () {
given:
def a = new Athing()
def res
def mock = GroovyMock (Zthing) { //, global:true
1*execute() >> {println "stub called"; res=true}
}
a.z = mock
when:
a.doit()
then:
res == true
}
I created the mock and set the interaction expectation (1*) and stubbed response, which sets my external res to some string so I can test for that.
Because the instance of 'a' has an embedded 'z' instance, I overwrite the a.z reference to point to the mock. I then call the SUT in the when clause, and check that res has been set. This does work.
However my real class/test still refuse to work. So my AORule has a DynamicRule reference
class AORule implements org.easyrules.api.Rule {
//setup delegate dynamicRule and make it a part of this ActiveObject
#Delegate DynamicRule rule
AORule (name, description=null) {
rule = new DynamicRule (name, description ?: "Basic Active Object Rule")
}
AORule () {
rule = new DynamicRule ()
} ....
where the execute method in AORule look like this
void execute () {
active_execute()
}
/**
* Active method manages async action through object inside through hidden actor.
* variable 'rule' is the variable we are protecting. Runs either any dynmicExecution closure
* where defined or just runs the standard class execute method
*
* #return void
*/
#ActiveMethod
void active_execute () {
//rule.execute()
if (rule.dynamicExecution != null) {
log.debug "activeExec : running dynamicExecution closure "
rule.dynamicExecute() //should call closure, where this is defined
}
else {
log.debug "activeExec : running std Execution action "
rule.execute()
}
} ....
My test for this looks like this:
def "set execution closure using GroovyMock to Stub out dynamicExecute action " () {
given:"setup of stub for testing "
def mockres
def mock = GroovyMock (DynamicRule) { //, global:true
1*dynamicExecute() >> {-> println "stub called"; mockres = "did nothing" }
0*execute()
}
aorule.rule = mock
when : "execution passing closure value at same time "
//have to run new, actions etc in scope of class stub
//def rule = new AORule ()
aorule.setDynamicExecution {println "hi"}
aorule.execute()
then : "test execute closure ran as expected "
mockres == "did nothing"
}
The test doesn't work correctly - the assertion shows mockres to be null (not being set).
I thought it might be because the activeEvaluate is internally checking on activeEvaluation closure is set, so I tried changing the GroovyMock to a GroovySpy (so that my aorule.setDynamicExecution call should work), and it still fails.
I can't seem to see where I am going here. My simple example seems to work and my real test doesn't.
I also tried brute force and used metaClass to hack an execute closure to set mockres, and that didn't get called either.

Saving argument method with MOP

I am doing some integration tests with Spock with 3rd party apps. Now I am struggling with a problem that I am not sure wether I am approaching the issue properly or not.
In one of the tests I am connecting to a 3rd party service to get some information in an array. Then each of these items are passed to another method to process them individually.
def get3rdPartyItems = {
[item1, item2, item3]
}
def processItem = { item ->
//do something with item
}
get3rdPartyItems.each {
processItem(it)
}
Then I have a test that connects to real 3rd party service using the method get3rdPartyItems() in which I am testing that processItem is called as many times as items has returned the method get3rdPartyItems().
What I am trying to do is to save one of the items as #Shared variable to write another test to know that the item is processed properly as I don't want to mock the content retrieved from the 3rd party service as I want real data.
Basically, this is what I am doing:
#Shared def globalItem
MyClass.metaClass.processItem = { i ->
if (!globalItem)
globalItem = i
//And now I would need to call the original method processItem
}
Any clue how to achieve this? I am probably overheading too much so I am open to change the solution.
Not sure if this is what you want, as it's hard to see your existing structure from the code and the code isn't runnable as-is, but given this class:
class MyClass {
def get3rdPartyItems = {
['item1', 'item2', 'item3']
}
def processItem( item ) {
println item
//do something with item
}
def run() {
get3rdPartyItems().each {
processItem( it )
}
}
}
You can do this:
def globalItem
def oldProcessItem = MyClass.metaClass.getMetaMethod("processItem", Object)
MyClass.metaClass.processItem = { item ->
if (!globalItem) {
println "Setting global item to $item"
globalItem = item
}
oldProcessItem.invoke( delegate, item )
}
def mc = new MyClass()
new MyClass().run()
Just as a matter of concision, that should be the way of passing the parameters to the metamethod in case you pass multiple parameters:
def globalItem
def oldProcessItem = MyClass.metaClass.getMetaMethod("processItem", ["",[:]] as Object[])
MyClass.metaClass.processItem = { String p1, Map p2 ->
if (!globalItem) {
println "Setting global item to $item"
globalItem = p2
}
oldProcessItem.invoke( delegate, [p1,p2] as Object[] )
}
def mc = new MyClass()
new MyClass().run()

How to alias the methods in a Groovy Category class

I created a class: NumberHelper
it has method: roll(num)
and I want to alias it, such as rollOnce, so I wrote:
static def rollOnce = NumberHelper.&roll
And the program throw an exception when I call rollOnce.
How to do this in groovy?
More Detail:
First, we implement Number class for our own business, in Java
def userBuildScript = findScript(name) as Closure
use (NumberHelper, StringHelper, UserHelper){
// first make the user object
// then
userBuildScript.call(preBuildUser, businessNumberObject)
}
and we wrote a category class for our Number class, it is the NumberHelper above.
and in the build script:
user(someRole) { user, number ->
it.someProperty = number.roll() // here, an exception throw
}
groovy.lang.MissingMethodException: No signature of method: xxx.xx.x.user.biz.Number,roll() is applicable for argument types
are these info enough to help me find the reason?
And thanks for answering, thanks:)
What you have should work as long as the original roll method is also static. This works fine for me in groovy 1.8.6:
class NumberHelper {
static def roll(num) {
return new Random().nextInt(num) + 1
}
static def rollOnce = NumberHelper.&roll
}
def roll = NumberHelper.roll(6)
assert roll <= 6 && roll >= 1
rollOnce = NumberHelper.rollOnce(10)
assert rollOnce <= 10 && rollOnce >= 1

Resources