Unit test case for Domain class ( testing constraints) - Grails - grails

I am actually new in the world of Grails. I am trying to write a test case for domain class which is having some constraints . I am getting a Null pointer exception on my object when i am trying to run my unit test. On debugging I got to know that there is something fishy with my toString method which is causing the object to set as Null. How should I move ahead ? Any help is highly appreciated.
Here is my domain class:
#MultiTenant
class OrderCharge {
static scaffold = [
exclude: ['tenantId'],
]
static belongsTo = [
order: SalesOrder
]
MiscOrderCharges miscOrderCharges
Date lastUpdated
double quantity
double price
SapInvoiceRecord sapInvoice
static constraints = {
order(nullable: true)
quantity(min:1d)
miscOrderCharges()
sapInvoice(nullable: true)
}
String toString(){
def pattern = "\$##,###.00"
def currency = new DecimalFormat(pattern)
String rate = currency.format(miscOrderCharges.price)
return "$miscOrderCharges x$quantity"
}
}
Here is my Unit test case:
import grails.test.mixin.TestFor
import spock.lang.Unroll
import spock.lang.Specification
#TestFor(OrderCharge)
//#TestMixin(GroovyPageUnitTestMixin)
class ChargeSpec extends Specification {
def setup() {
mockForConstraintsTests(
OrderCharge, [
new OrderCharge(order: Mock(SalesOrder),
miscOrderCharges: Mock(MiscOrderCharges),
quantity: 1.0,
price:20.0
/*, sapInvoice: Mock(SapInvoiceRecord) */
)
]
)
}
void validateConstraints(obj, field, error) {
def validated = obj.validate()
if (error && error != 'valid') {
assert !validated
assert obj.errors[field]
assert error == obj.errors[field]
} else {
assert !obj.errors[field]
}
}
#Unroll("test inventory all constraints #field is #error")
def "test Charge all constraints"() {
given:
def obj = new OrderCharge("$field": val)
expect:
validateConstraints(obj, field, error)
where:
error |field |val
'nullable' |'orderCharge' |null
'nullable' |'sapInvoice' |null
'min' |'quantity' |-1
'min' |'price' |0
}
}
Thanks in advance.

The only thing that jumps out at me is your return in the toString().
return "$miscOrderCharges x$quantity"
You're using gStrings there. It's my understanding that individual variables can be referred to using simple $ notation, as in the format $somevariable, whereas expressions are in the format ${expression}.
In your statement x$quantity seems like a typo. Did you mean to multiply them as an expression like below?
return "${miscOrderCharges * quantity}"
See http://groovy.jmiguel.eu/groovy.codehaus.org/Strings+and+GString.html for more information.

Related

Spock testing: Too many invocation

I wrote service for manual requeuing events from one queue to another.
public class ReQueueService {
private final RabbitTemplate rabbitTemplate;
public void retry() {
InfoLog infoLog;
while (rabbitTemplate != null &&
(infoLog = (InfoLog) rabbitTemplate.receiveAndConvert(EVENT_WAITING_FOR_REQUEUE)) != null
) {
rabbitTemplate.convertAndSend(SOME_QUEUE, infoLog.getSomeEvent());
}
}
}
The problem I am facing is getting:
Too many invocations for:
1 * rabbitTemplate.convertAndSend(SOME_QUEUE, _ as SomeEvent) >> {
arguments ->
assert infoLog.getSomeEvent() == arguments[1]
} (2 invocations)
Matching invocations (ordered by last occurrence):
2 * rabbitTemplate.convertAndSend(SOME_QUEUE, ...
while my code in test looks like this:
class ReQueueServiceTest extends Specification {
def "should resend single event to some queue" () {
given:
InfoLog infoLog = Fixtures.createInfoLog()
def rabbitTemplate = Mock(RabbitTemplate){
receiveAndConvert(EVENT_WAITING_FOR_REQUEUE) >> { infoLog }
}
ReQueueService reSyncService = new ReQueueService(rabbitTemplate)
when:
reSyncService.retry()
then:
1 * rabbitTemplate.convertAndSend(SOME_QUEUE, _ as SomeEvent) >> {
arguments ->
assert infoLog.getSomeEvent() == arguments[1]
}
}
}
The question is why I have 2 invocations, if I stubb only one event?
EDIT:
link to repo with example: https://gitlab.com/bartekwichowski/spock-too-many
Thanks for the repo link. As soon as I could run the test and inspect the behaviour live, it was pretty easy to find out what was wrong. First I will make an educated guess about what you actually want to test:
The mock's receiveAndConvert method should return str when it is called first and then null when called again.
Subsequently you want to verify that the while loop runs exactly 1 iteration, i.e. that convertAndSend is called with exactly the parameters you expect.
This can be achieved by
receiveAndConvert("FOO") >>> [str, null]
1 * rabbitTemplate.convertAndSend("BAR", str) (no need for ugly assertions inside a stubbed method, the parameters are verified against your parameter constraints already)
If I refactor your specification a little bit for prettier variable names and less verbosity, it looks like this:
class ReSyncServiceTest extends Specification {
def "should resend single event to resource sync queue"() {
given:
def message = "someValue"
def rabbitTemplate = Mock(RabbitTemplate) {
receiveAndConvert("FOO") >>> [message, null]
}
when:
new ReSyncService(rabbitTemplate).retry()
then:
1 * rabbitTemplate.convertAndSend("BAR", message)
}
}
P.S.: Your version with the assertion inside does not return anything explicitly, but implicitly the result of the last assertion. Be careful with that. With >> { ... } you are stubbing the method result! It would always return true in the version you have in Git and the test only terminates because you added the 1 * limit. If it was not there, you would have an endless loop. Your code did not do what you thought it did. Maybe the Spock manual can help you there. :-)
P.P.S.: Maybe you want to refactor your application code to be a bit easier to understand and maintain and to be a little less "smart". Also there is no need to check that rabbitTemplate != null in every iteration, once should be enough. How about this?
#Slf4j
#Service
#AllArgsConstructor
public class ReSyncService {
private final RabbitTemplate rabbitTemplate;
public void retry() {
if (rabbitTemplate == null)
return;
String event;
while (null != (event = getEventFromQueue()))
rabbitTemplate.convertAndSend("BAR", event);
}
protected String getEventFromQueue() {
return (String) rabbitTemplate.receiveAndConvert("FOO");
}
}

Grails fail at test -app

I have my domain Class and my groovy class for unit test
class Product {
String product_code
String store
int price
String notes
//static hasOne = [description: Description]
static constraints = {
product_code blank:false, size: 1..15
price blank:false, scale: 2
store blank:false, size: 1..40
notes blank:true , size: 1..150
}
}
import org.apache.jasper.compiler.Node.ParamsAction;
import grails.test.mixin.*
import org.junit.*
import org.pricer.model.Product;
/**
* See the API for {#link grails.test.mixin.domain.DomainClassUnitTestMixin} for usage instructions
*/
#TestFor(Product)
class ProductTests {
void testSomething() {
if (Product.hasErrors()){
fail "not pass"
}else
assert "Pass"
}
}
when i try tu run test-app my ProductTest.testSomething i get
No signature of method: org.pricer.model.Product.hasErrors() is applicable for argument types: () values: []
Possible solutions: hasErrors(), getErrors(),
setErrors(org.springframework.validation.Errors), clearErrors(), hashCode()
groovy.lang.MissingMethodException: No signature of method: org.pricer.model.Product.hasErrors() is applicable for argument types: () values: []
Possible solutions: hasErrors(), getErrors(), setErrors(org.springframework.validation.Errors), clearErrors(), hashCode()
at
org.grails.datastore.gorm.GormStaticApi.methodMissing(GormStaticApi.groovy:97)
at org.pricer.ProductTests.testSomething(ProductTests.groovy:20)
You didn't instantiate domain class Product in your test. Try f.e.:
void testSomething() {
def product = new Product()
if (product.hasErrors()){
//do something
}
}
hasErrors() is an instance method. When you call Product.hasErrors() you're calling a class/static method, which in this case, does not exist.
So, as majkelo said, you need a Product instance first. But, you also need to trigger domain class validation so that if there are errors, hasErrors() will report them.
def product = new Product(product_code: 'ABC', store: 'StackOverflow', price: 1000000)
product.validate() /* You can also call product.save() to validate. */
if(product.hasErrors()) {
/* Do your thing */
}
A short-cut
You can combine validation and error checking like this:
if(product.validate()) {
/* validation passed. */
} else {
/* validation failed. */
}

What is the idiomatic way to run a Specification over multitple implementations with Spock?

Let's say I have a Joiner interface:
interface Joiner {
String join(List<String> l);
}
And two implementations of it:
class Java8Joiner implements Joiner {
#Override String join(List<String> l) { String.join("", l); }
}
class GroovyJoiner implements Joiner {
#Override String join(List<String> l) { l.join('') }
}
What is the best way to check that theses two implementation, or more, pass the same tests?
Basically, I want to run all the tests defined by JoinerSpecification with a Java8Joiner, then a GroovyJoiner, and so on...
class JoinerSpecification extends Specification {
#Subject
final def joiner = // Joiner instance here
def "Joining #list -> #expectedString"(List<String> list, String expectedString) {
expect:
joiner.join(list) == expectedString
where:
list | expectedString
[] | ''
['a'] | 'a'
['a', 'b'] | 'ab'
}
}
It is perfectly fine to refactor JoinerSpecification if needed.
My primary goals are:
Maintainable test code (with as little boilerplate as possible)
Clear error messages (which test of which implementation is failing)
Easy to run from the IDE
Edit 1 (15/06/2015)
Reworded my question & added some details to make it clearer.
Opal's proposal is interesting but is impractical. Not being able to use then blocks is a showstopper.
Lets try a self-answer using another approach. Since the goal is to execute the same specification on several implementations of the same interface, why not try to use good old inheritance ?
abstract class AbstractJoinerSpec extends Specification {
abstract Joiner getSubject()
#Unroll
def "Joining #list -> #expectedString"(List<String> list, String expectedString) {
given:
def joiner = getSubject()
expect:
joiner.join(list) == expectedString
where:
list | expectedString
[] | ''
['a'] | 'a'
['a', 'b'] | 'ab'
}
}
class Java8JoinerSpec extends AbstractJoinerSpec {
#Override
Joiner getSubject() { new Java8Joiner() }
}
class GroovyJoinerSpec extends AbstractJoinerSpec {
#Override
Joiner getSubject() { new Java8Joiner() }
}
Basically, the only abstract method is getSubject and all the inherited test cases are executed by Spock (I have not been able to find this feature in the documentation but it does work).
Pros
It only requires creating a tiny class for each implementation and the specification code remains clean.
The full power of Spock can be used
Error messages and reports are clear (you know which test failed for which implementation)
Cons
Running a given test for a given implementation from the IDE is not easy. You have to copy/paste the test case into the non abstract specification or remove the abstract modifiers and implement the getSubject method.
I thing the trade-off acceptable since you don't manually run/debug an implementation that often. Keeping the code clean, and having meaningful report worth this inconvenience.
What would be very useful here is comparison chaining but, as far as I know it's not implemented in groovy, see here. Since Subject purpose according to the docs is pure informational I've come up with the following ideas:
#Grab('org.spockframework:spock-core:0.7-groovy-2.0')
#Grab('cglib:cglib-nodep:3.1')
import spock.lang.*
class Test extends Specification {
def 'attempt 1'() {
given:
def joiners = [new GroovyJoiner(), new Java8Joiner()]
expect:
joiners.every { it.join(list) == expectedString }
where:
list | expectedString
[] | ''
['a'] | 'a'
['a', 'b'] | 'ab'
}
def 'attempt 2'() {
given:
def gJoiner = new GroovyJoiner()
def jJoiner = new Java8Joiner()
expect:
[gJoiner.join(list), jJoiner.join(list), expectedString].toSet().size() == 1
where:
list | expectedString
[] | ''
['a'] | 'a'
['a', 'b'] | 'ab'
}
}
interface Joiner {
String join(List<String> l);
}
class Java8Joiner implements Joiner {
#Override String join(List<String> l) { String.join("", l); }
}
class GroovyJoiner implements Joiner {
#Override String join(List<String> l) { l.join('') }
}
In the attempt 1 I'm just checking if every element on the list is equal to expectedString. It looks nice however on error it's not verbose enough. Any element may fail and there's no trace which one.
The attempt 2 method makes use of Set. Since all the results should be equal there'll be only one element left in the collection. In prints verbose info on test failure.
What also comes to my head is guava's ComparisonChain but no idea if it would be useful as well as it's another project dependency.
Unfortunately, there is no way to create a cartesian product of two lists declaratively in Spock. You have to define your own Iterable that will provide the values for your variables.
There is a more readable (using Spock tabular data definition) way to define the data, if you are willing to sacrifice terseness for readability. Let me know if that interests you. Otherwise here is a solution that lets you define everything declaratively, without duplication, but you lose the nice tabular definitions of Spock.
If your implementation is stateless, i.e. it does not keep state, you can get away with using #Shared instances of Joiner:
import spock.lang.Shared
import spock.lang.Specification
import spock.lang.Unroll
interface Joiner {
String join(List<String> l);
}
class Java8Joiner implements Joiner {
#Override
String join(List<String> l) { String.join("", l); }
}
class GroovyJoiner implements Joiner {
#Override
String join(List<String> l) { l.join('') }
}
class S1Spec extends Specification {
#Shared
Joiner java8Joiner = new Java8Joiner()
#Shared
Joiner groovyJoiner = new GroovyJoiner()
List<Map> transpose(Map<List> mapOfLists) {
def listOfMaps = [].withDefault { [:] }
mapOfLists.each { k, values ->
[values].flatten().eachWithIndex { value, index ->
listOfMaps[index][k] = value
}
}
listOfMaps
}
Iterable distribute(List<Joiner> joiners, Map<String, List> data) {
def varsForEachIteration = transpose(data)
new Iterable() {
#Override
Iterator iterator() {
[joiners, varsForEachIteration].combinations().iterator()
}
}
}
#Unroll
def "Joining with #joiner #list -> #expectedString"() {
expect:
joiner.join(list) == expectedString
where:
[joiner, data] << distribute([java8Joiner, groovyJoiner], [
list : [[], ['a'], ['a', 'b']],
expectedString: ['', 'a', 'ab']
])
and:
list = data.list
expectedString = data.expectedString
}
}

Where query in Grails not returning records

Update: I found the problem. I needed to save the "train" domain as follows.
train.save(flush: true)
I needed to provide a flush, as well.
I edited to include the information requested. Thanks.
I have two domain classes as follows.
class Train {
String name
static hasMany = [passengers: Person]
. . .
}
class Person {
String firstName
String lastName
. . .
}
I am trying to use a where query to look for passengers with a given first name. Here is the full integration test code. The first query, looking for the passenger, does not work. The second one, looking for the train by name, works.
I am using Grails 2.2.1 and am running the test inside of my IDE, Groovy/Grails Tool Suite 3.2. I am not bootstrapping data, but am adding data in the test. Please see the testSomething code below.
Here is the test code.
import grails.converters.*
import static org.junit.Assert.*
import org.junit.*
class TrainIntegrationTests {
#Before
void setUp() {
// Setup logic here
}
#After
void tearDown() {
// Tear down logic here
}
#Test
void testSomething() {
def person1 = new Person()
person1.firstName = "George"
person1.lastName = "Romero"
person1.save();
println "person1.id: " + person1.id
def person2 = new Person()
person2.firstName = "Jane"
person2.lastName = "Smith"
person2.save();
def train = new Train()
train.name = "This Train"
train.addToPassengers(person1)
train.addToPassengers(person2)
train.save()
// This prints out 2.
println "passengers size" + train.passengers.size()
// This does not work. No results are returned.
def query = Train.where {
passengers {
firstName == 'George'
}
}
def qResults = query.list()
// No results
println "qResults: " + qResults
// This does work. Results returned.
def query1 = Train.where {
name == 'This Train'
}
def qResults1 = query1.list()
// Returns results.
println "qResults1: " + qResults1
// Don't really care about assert results yet.
// Just looking at the print outs and seeing how this all works.
assert true
}
}
What am I missing in the passengers query?
All,
I found the problem. I needed to save with a flush, as well.
Instead of . . .
train.save()
I used . . .
train.save(flush: true)
The query began working after that.

GORM bidirectional One-to-Many

I'm trying to create a bidirectional one-to-many relationship between Foo and Bar domains in GORM.
Here's what I have so far:
class Bar {
static belongsTo = [foo: Foo]
}
class Foo {
Set bars = []
static hasMany = [bars: Bar]
}
The problem that I'm having is when I go to use the relationship methods, they don't seem to behave the way that I think they should. For example, you would think a statement like "foo.bars.add(bar)" would also set the foo field on the bar argument. But when I call "bar.foo.id" I'm told that the foo field is null. I can fix that problem if I use "bar.foo = foo" instead of "foo.bars.add(bar)". Unfortunately, when I call "foo.bars.size()" it tells me that it is 0.
To get a clearer picture of what I'm talking about, here are my tests:
def testFoo() {
def foo = new Foo()
def bar = new Bar()
foo.bars.add(bar)
println "foo.bars.size() = ${foo.bars.size()}"
println "bar.id = ${bar.id}"
for(def xbar : foo.bars) {
println "bar.id = ${xbar.id}"
}
println "foo.id = ${foo.id}"
println "bar.foo.id = ${bar?.foo?.id}" // <- is null
}
def testBar() {
def foo = new Foo()
def bar = new Bar()
bar.foo = foo
println "foo.bars.size() = ${foo.bars.size()}" // <- is 0
println "bar.id = ${bar.id}"
for(def xbar : foo.bars) {
println "bar.id = ${xbar.id}"
}
println "foo.id = ${foo.id}"
println "bar.foo.id = ${bar?.foo?.id}"
}
What am I doing wrong?
Note: I'm running this through an integration test. I've also found that "foo.addToBars(bar)" works the way that I think "foo.bars.add(bar)" and "bar.foo = foo" should work.
Update Here's a quick hack I did that does what I want (using Hibernate and JPA):
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedList;
import stuff.Foo;
public class MyList<Bar> extends LinkedList {
private Foo foo;
public MyList(Foo foo) {
this.foo = foo;
}
#Override
public boolean add(Object obj) {
boolean result = super.add(obj);
try {
Method barMethod = obj.getClass().getDeclaredMethod("setFoo", Foo.class);
barMethod.invoke(obj, foo);
}
catch(NoSuchMethodException noSuchMethod) {
noSuchMethod.printStackTrace();
}
catch(InvocationTargetException invocationTarget) {
invocationTarget.printStackTrace();
}
catch(IllegalAccessException illegalAccess) {
illegalAccess.printStackTrace();
}
return result;
}
}
If you read the documentation, you'll learn that, as you found out but are still questioning, the correct way to add items to a collection so they are persisted correctly is to use the addTo* methods.
So in your case, when you said that using addToBars worked, that's the right way to do this. That said, there are some performance hits you take with that. Another way is to do:
bar.foo = foo
bar.save()
The downside is that foo will not contain bar in its existing Set. You'd have to pull it from the database again. It's a bit of a give and take and you just use the best method for your situation.

Resources