You May Also Like
Private fields and methods are not private in groovy
- byTomasz Kalkosiński
- July 12, 2012
I used to code in Java before I met groovy. Like most of you, groovy attracted me with many enhancements. This was to my surprise to discover that method visibility in groovy is handled different than Java!
Consider this example:
class Person {
private String name
public String surname
private Person() {}
private String signature() { "${name?.substring(0, 1)}. $surname" }
public String toString() { "I am $name $surname" }
} How is this class interpreted with Java?
- Person has private constructor that cannot be accessed
- Field "name" is private and cannot be accessed
- Method signature() is private and cannot be accessed
Let's see how groovy interpretes Person:
public static void main(String[] args) {
def person = new Person() // constructor is private - compilation error in Java
println(person.toString())
person.@name = 'Mike' // access name field directly - compilation error in Java
println(person.toString())
person.name = 'John' // there is a setter generated by groovy
println(person.toString())
person.@surname = 'Foo' // access surname field directly
println(person.toString())
person.surname = 'Bar' // access auto-generated setter
println(person.toString())
println(person.signature()) // call private method - compilation error in Java
} I was really astonished by its output:
I am null null
I am Mike null
I am John null
I am John Foo
I am John Bar
J. Bar As you can see, groovy does not follow visibility directives at all! It treats them as non-existing. Code compiles and executes fine. It's contrary to Java. In Java this code has several errors, pointed out in comments.
I've searched a bit on this topic and it seems that this behaviour is known since version 1.1 and there is a bug report on that: http://jira.codehaus.org/browse/GROOVY-1875. It is not resolved even with groovy 2 release. As Tim Yates mentioned in this Stackoverflow question: "It's not clear if it is a bug or by design". Groovy treats visibility keywords as a hint for a programmer.
I need to keep that lesson in mind next time I want to make some field or method private!
Testing Kotlin with Spock Part 2 – Enum with instance method
- byDominik Przybysz
- May 28, 2018
Thought static method can’t be easy to mock, stub nor track? Wrong!
- byTomasz Przybysz
- April 6, 2013
In pure Java world it is still a struggle. But Groovy allows you to do that really simple. Well, not groovy alone, but with a great support of Spock.
Lets move on straight to the example. To catch some context we have an abstract for the example needs. A marketing project with a set of offers. One to many.
import spock.lang.Specification
class OfferFacadeSpec extends Specification {
OfferFacade facade = new OfferFacade()
def setup() {
GroovyMock(Project, global: true)
}
def 'delegates an add offer call to the domain with proper params'() {
given:
Map params = [projId: projectId, name: offerName]
when:
Offer returnedOffer = facade.add(params)
then:
1 * Project.addOffer(projectId, _) >> { projId, offer -> offer }
returnedOffer.name == params.name
where:
projectId | offerName
1 | 'an Offer'
15 | 'whasup!?'
123 | 'doskonała oferta - kup teraz!'
}
}So we test a facade responsible for handling "add offer to the project" call triggered somewhere in a GUI.We want to ensure that static method Project.addOffer(long, Offer) will receive correct params when java.util.Map with user form input comes to the facade.add(params).
This is unit test, so how Project.addOffer() works is out of scope. Thus we want to stub it.
The most important is a GroovyMock(Project, global: true) statement.
What it does is modifing Project class to behave like a Spock's mock.
GroovyMock() itself is a method inherited from Specification. The global flag is necessary to enable mocking static methods.
However when one comes to the need of mocking static method, author of Spock Framework advice to consider redesigning of implementation. It's not a bad advice, I must say.
Another important thing are assertions at then: block. First one checks an interaction, if the Project.addOffer() method was called exactly once, with a 1st argument equal to the projectId and some other param (we don't have an object instance yet to assert anything about it).
Right shit operator leads us to the stub which replaces original method implementation by such statement.
As a good stub it does nothing. The original method definition has return type Offer. The stub needs to do the same. So an offer passed as the 2nd argument is just returned.
Thanks to this we can assert about name property if it's equal with the value from params. If no return was designed the name could be checked inside the stub Closure, prefixed with an assert keyword.
Worth of mentioning is that if you want to track interactions of original static method implementation without replacing it, then you should try using GroovySpy instead of GroovyMock.
Unfortunately static methods declared at Java object can't be treated in such ways. Though regular mocks and whole goodness of Spock can be used to test pure Java code, which is awesome anyway :)No matter why, no matter is it a good idea. Sometimes one just wants to check or it's necessary to be done. Mock a static method, woot? Impossibru!
In pure Java world it is still a struggle. But Groovy allows you to do that really simple. Well, not groovy alone, but with a great support of Spock.
Lets move on straight to the example. To catch some context we have an abstract for the example needs. A marketing project with a set of offers. One to many.
import spock.lang.Specification
class OfferFacadeSpec extends Specification {
OfferFacade facade = new OfferFacade()
def setup() {
GroovyMock(Project, global: true)
}
def 'delegates an add offer call to the domain with proper params'() {
given:
Map params = [projId: projectId, name: offerName]
when:
Offer returnedOffer = facade.add(params)
then:
1 * Project.addOffer(projectId, _) >> { projId, offer -> offer }
returnedOffer.name == params.name
where:
projectId | offerName
1 | 'an Offer'
15 | 'whasup!?'
123 | 'doskonała oferta - kup teraz!'
}
}So we test a facade responsible for handling "add offer to the project" call triggered somewhere in a GUI.We want to ensure that static method Project.addOffer(long, Offer) will receive correct params when java.util.Map with user form input comes to the facade.add(params).
This is unit test, so how Project.addOffer() works is out of scope. Thus we want to stub it.
The most important is a GroovyMock(Project, global: true) statement.
What it does is modifing Project class to behave like a Spock's mock.
GroovyMock() itself is a method inherited from Specification. The global flag is necessary to enable mocking static methods.
However when one comes to the need of mocking static method, author of Spock Framework advice to consider redesigning of implementation. It's not a bad advice, I must say.
Another important thing are assertions at then: block. First one checks an interaction, if the Project.addOffer() method was called exactly once, with a 1st argument equal to the projectId and some other param (we don't have an object instance yet to assert anything about it).
Right shit operator leads us to the stub which replaces original method implementation by such statement.
As a good stub it does nothing. The original method definition has return type Offer. The stub needs to do the same. So an offer passed as the 2nd argument is just returned.
Thanks to this we can assert about name property if it's equal with the value from params. If no return was designed the name could be checked inside the stub Closure, prefixed with an assert keyword.
Worth of mentioning is that if you want to track interactions of original static method implementation without replacing it, then you should try using GroovySpy instead of GroovyMock.
Unfortunately static methods declared at Java object can't be treated in such ways. Though regular mocks and whole goodness of Spock can be used to test pure Java code, which is awesome anyway :)
