Stan Svec
Stan Svec

Reputation: 499

How to print statement from asserted method or closure in Groovy

Is it somehow possible to inline statement from closure or method into an assertion so it can be printed when the assertion fails?

If we have simple statement like assert 10 == (20 - 11) then Groovy's power assert prints it nicely like:

assert 10 == (20 - 11)
          |      |
          false  9

However if we extract the statement into a closure like:

def c = { arg -> arg == (20 - 11) }
assert c(10)

then the output will be much less informative:

assert c(10)
       |
       false

I'm developing custom specific test framework and the use case is to have custom assertions represented as boolean closures or methods and run the assertion from one place.

Upvotes: 2

Views: 1219

Answers (1)

Rao
Rao

Reputation: 21379

You were getting such output becuase, closure is returning boolean and assert does look for true.

Approach #1 : If you want change the ouput, then may be you can pass the two arguments to closure instead of one argument as shown below. Of course, you may not want to compare equality with static number in your framework, so the second argument make sense.

def c = { arg1, arg2 -> arg1 == arg2 }  
assert c(10, 20-11), 'comparison failed'

Output:

java.lang.AssertionError: Comparison failed. Expression: c.call(10, (20 - 11)) at Script1.run(Script1.groovy:2)

Approach #2: Here changed closure name appropriately, and doing the assertion inside itself. Since its name is assertEqual, it may unlikely misused for other assertions such as >, <.

def assertEqual = { arg1, arg2 -> assert arg1 == arg2, "Comparison failed: ${arg1} vs ${arg2}" }  
assertEqual(10, 20-11)

Output:

java.lang.AssertionError: Comparison failed: 10 vs 9. Expression: (arg1 == arg2). Values: arg1 = 10, arg2 = 9
at Script1$_run_closure1.doCall(Script1.groovy:1)
at Script1.run(Script1.groovy:2)

You write more closures in this manner, such as assertGreaterThan assertLessThan for specific operations.

Approach #3: Here you can even pass what should be the error message to the closure.

def assertEqual = { arg1, arg2, message -> assert arg1 == arg2, message(arg1, arg2) }
assertEqual(10, 20-11) {op1, op2 -> "$op1 is not equal to $op2"}

Output:

java.lang.AssertionError: 10 is not equal to 9. Expression: (arg1 == arg2). Values: arg1 = 10, arg2 = 9
at Script1$_run_closure1.doCall(Script1.groovy:1)
at Script1.run(Script1.groovy:2)

Approach #4 Another variant where user can pass operation, and message. You may not only do equal, but also other operations as well. So, changing the closure name to myAssert.

def myAssert = { arg1, arg2, expression -> expression(arg1, arg2) }
//Greater than
myAssert(10, 20-11) {op1, op2 -> assert op1 > op2, "$op1 is not greater than $op2" }
//Less than
myAssert(10, 20-11) {op1, op2 -> assert op1 < op2, "$op1 is not less than $op2" }
//Equal
myAssert(10, 20-11) {op1, op2 -> assert op1 == op2, "$op1 is not equal to $op2" }

Output:

java.lang.AssertionError: 10 is not less than 9. Expression: (op1 < op2). Values: op1 = 10, op2 = 9
at Script1$_run_closure2.doCall(Script1.groovy:2)
at Script1$_run_closure1.doCall(Script1.groovy:1)
at Script1.run(Script1.groovy:2)

If you want to go with simple approach and just use equal assert, then Approach #2 is right one. Of course, you are the better one to choose which one suits better for your need.

Upvotes: 1

Related Questions