Share code between features in spock framework - groovy

I'm using spock for test.
For a specification S, I have three distinct features F1, F2, F3.
I have my features with given, when, then part but I want to share the code between given and when since that's almost the same except for the then part
pseudo code:
class S extends Specification {
def 'f1' () {
given:
redundantcode('file1')
then:
redundantcode_2_with_no_param
when:
valuable_code_1
}
def 'f2' () {
given:
redundantcode('file2')
then:
redundantcode_2_with_no_param
when:
valuable_code_2
}
def 'f3' () {
given:
redundantcode('file3')
then:
redundantcode_2_with_no_param
when:
valuable_code_3
}
}
I'm looking for a way to avoid duplicated code in given and when part.

You can just write a method in you test class. E.g.:
void redundantcode_2_with_no_param() {…}
Note that if you use "def" instead of "void", whatever the last line in your method will return, will be returned from the method. That might lead to a failing test, if it is null.

Are you perhaps looking for a parameterized testing approach using Data Tables or data pipes? Data Driven Testing
For example, you could do:
def 'f1' () {
when:
redundantcode(fileName)
then:
redundantcode_with_no_param
then:
valuable_code_3
where:
fileName << ['file1', 'file2', 'file3']
}
This is assuming your valuable_code_3 is somewhat repeatable as well. If you have a comparison somewhere in there you could expand it to have a second value in the where clause of "result << ['expectedResult1', 'expectedResult2', 'expectedResult3'] etc. etc.

Related

Declare multiple variables in one line in Spock when: block

I would like to know how I can define, without initializing, multiple variables in one line in Spock spec as shown below.
I have tried:
import spock.lang.Specification
class exampleSpec extends Specification {
def "foo"() {
when:
def a, b
a = 0
b = 1
then:
a != b
}
}
But this fails when accessing b:
No such property: b for class: ....
I have managed to get the following to work:
def (a, b) = []
But I'd like something better.
Any help is greatly appreciated!
I am using:
Groovy Version: 2.4.3 JVM: 1.8.0_45 Vendor: Oracle Corporation OS: Linux
I fear that cannot be done in any of the blocks (like given:, setup:, when:). There is an easy work around.
#Grab(group='org.spockframework', module='spock-core', version='0.7-groovy-2.0')
import spock.lang.Specification
class ExampleSpec extends Specification {
def "foo"() {
def a, b
when:
a = 0
b = 1
then:
a != b
}
}
Move the declaration out of when:/given:/setup: block and have them as method variables. The setup:/given: label is optional and may be omitted, resulting in an implicit setup block.
Although this works, I would like to know the reason why this did not work otherwise. You can create an issue in github.
You should use the where: block to pass parameters. There's no def required because they're passed as an argument, if you're feeling fancy you can even have a test that is run multiple times.
def "Use where to pass test data"(){
expect: 1 == myNumber
2 == myOther1
where: myNumber = 1
myOther1 = 2
}
Here's a link to some other examples I've written that show how to pass data to your tests. If you really like multiple assignment (even though it's not a good idea) here's how you could use it in a where: block.
If you're curious about the various blocks here is a summary of everything I've read. Don't take my word for it, here's some official documentation.
You might be happy to know that this issue has been raised already, but it hasn't seen any activity in the last month. My assumption is that something about multiple assignment doesn't agree with the AST transformations that Spock uses on your code.

how to use testrunner.fail in groovy class for soapui

I am trying to fail the test case if string values are not same.I have created a class and a method to compare the string values.
public class test1 {
public String onetwo(str1,str2)
{
def first = str1
def second=str2
if (first==second)
{
return "Strings are same"
}
else
{
testrunner.fail("String Values are not same")
}
}
public String fail(reason)
{
return "implementation of method1"+reason
}
}
def objone =new test1()
def result = objone.onetwo('Soapui','Soapui')
def result1 = objone.onetwo('Soapui','SoapuiPro')
while executing it i am getting below message for last line of above code
ERROR:groovy.lang.MissingPropertyException: No such property: testrunner for class: test1
Please suggest how to use testrunner.fail or any other way to fail the test case if strings are not same.
Thank You
It can't find SoapUI's testrunner because you're accessing it inside your own class. (Note that the error message is trying to find test1.testrunner, which of course does not exist.) If you accessed testrunner from the top level of the script (where you define your variables) it should work.
If you still want to have a reusable class/method, an easy fix would be to have it return a boolean or an error message, and then you call testrunner.fail if your method returns false/error. Something like this (although a boolean return might make for cleaner code):
public class test1 {
public String onetwo(str1,str2)
{
def first = str1
def second=str2
if (first==second)
{
return "Strings are same"
}
else
{
return "String Values are not same"
}
}
...
}
def objone =new test1()
def result = objone.onetwo('Soapui','Soapui')
def result1 = objone.onetwo('Soapui','SoapuiPro')
if (result != "Strings are same")
{
testrunner.fail(result)
}
...
This thread from another site also describes a much more complex solution of making reusable Groovy libraries for SoapUI.
If two strings are to be compared in groovy script test step, then it is not required to write a class, instead can be achieved with below statement.
Matching Samples - note that nothing happens on successful assertion
String compare and fail if not equal
assert 'Soapui' == 'Soapui', "Actual and expected does not match"
Another example - with boolen
def result = true;assert result, "Result is false"
Non-Matching example - test fails on failure
Strings not matching, and shows error message
assert 'Soapui' == 'SoapuiPro', "Actual and expected does not match"
Another example with non zero test
def number=0;assert number, "Number is zero"
If you need only example of the class and like to access testRunner object, then we need pass it either to the class or to the method where testRunner is needed. Otherwise, other class do not know about the objects that are available to groovy script.
Here is some more information on the objects availability at various level of test case hierarchy.
When soapUI is started, it initializes certain variables and are available at Project, Suite, Test case, Setup Script, Teardown script etc., If you open the script editor you would see the objects available there.
For instance, groovy script test step has log, context, testRunner, testCase objects. However, if some one creates a class with in Groovy Script test step, those objects are not available with in that user defined class.

prefix println statements in groovy

I'd like to achieve the following goals using groovy:
Prepend (prefix) all println statements in groovy with the current time
I want the continue printing those println statements to print on standard out (console in my case).
I want to do it at one generic place, so that I don't have to individually modify all of these println statements.
Is there anything (like groovy aspect, log4j console appender etc.) that I could use to have all println statements prepend the time?
Metaprogramming. You could have PrintStream.metaClass.invokeMethod intercept the call to the println method and add the date to the passed in string.
Something like this, adapted from example code in Subramaniam's "Programming Groovy":
System.out.metaClass.invokeMethod = {String name, args ->
def validMethod = System.out.metaClass.getMetaMethod(name, args)
if (! validMethod)
{
return System.out.metaClass.invokeMissingMethod(delegate,name,args)
}
if ( validMethod.name == 'println')
{
args[0] = "${(new Date()).toString()} : ${args[0]}".toString()
}
validMethod.invoke(delegate,args)
}

Test Groovy class that uses System.console()

I have a groovy script that asks some questions from the user via a java.io.console object using the readline method. In addition, I use it to ask for a password (for setting up HTTPS). How might I use Spock to Unit Test this code? Currently it complains that the object is a Java final object and can not be tested. Obviously, I'm not the first one trying this, so thought I would ask.
A sketch of the code would look something like:
class MyClass {
def cons
MyClass() {
cons = System.console()
}
def getInput = { prompt, defValue ->
def input = (cons.readLine(prompt).trim()?:defValue)?.toString()
def inputTest = input?.toLowerCase()
input
}
}
I would like Unit Tests to test that some mock response can be returned and that the default value can be returned. Note: this is simplified so I can figure out how to do the Unit Tests, there is more code in the getInput method that needs to be tested too, but once I clear this hurdle that should be no problem.
EDITED PER ANSWER BY akhikhl
Following the suggestion, I made a simple interface:
interface TestConsole {
String readLine(String fmt, Object ... args)
String readLine()
char[] readPassword(String fmt, Object ... args)
char[] readPassword()
}
Then I tried a test like this:
def "Verify get input method mocking works"() {
def consoleMock = GroovyMock(TestConsole)
1 * consoleMock.readLine(_) >> 'validResponse'
inputMethods = new MyClass()
inputMethods.cons = consoleMock
when:
def testResult = inputMethods.getInput('testPrompt', 'testDefaultValue')
then:
testResult == 'validResponse'
}
I opted to not alter the constructor as I don't like having to alter my actual code just to test it. Fortunately, Groovy let me define the console with just a 'def' so what I did worked fine.
The problem is that the above does not work!!! I can't resist - this is NOT LOGICAL! Spock gets 'Lost' in GroovyMockMetaClass somewhere. If I change one line in the code and one line in the test it works.
Code change:
From:
def input = (cons.readLine(prompt).trim()?:defValue)?.toString()
To: (add the null param)
def input = (cons.readLine(prompt, null).trim()?:defValue)?.toString()
Test change:
From:
1 * consoleMock.readLine(_) >> 'validResponse'
To: (again, add a null param)
1 * consoleMock.readLine(_, null) >> 'validResponse'
Then the test finally works. Is this a bug in Spock or am I just out in left field? I don't mind needing to do whatever might be required in the test harness, but having to modify the code to make this work is really, really bad.
You are right: since Console class is final, it could not be extended. So, the solution should go in another direction:
Create new class MockConsole, not inherited from Console, but having the same methods.
Change the constructor of MyClass this way:
MyClass(cons = null) {
this.cons = cons ?: System.console()
}
Instantiate MockConsole in spock test and pass it to MyClass constructor.
update-201312272156
I played with spock a little bit. The problem with mocking "readLine(String fmt, Object ... args)" seems to be specific to varargs (or to last arg being a list, which is the same to groovy). I managed to reduce a problem to the following scenario:
Define an interface:
interface IConsole {
String readLine(String fmt, Object ... args)
}
Define test:
class TestInputMethods extends Specification {
def 'test console input'() {
setup:
def consoleMock = GroovyMock(IConsole)
1 * consoleMock.readLine(_) >> 'validResponse'
when:
// here we get exception "wrong number of arguments":
def testResult = consoleMock.readLine('testPrompt')
then:
testResult == 'validResponse'
}
}
this variant of test fails with exception "wrong number of arguments". Particularly, spock thinks that readLine accepts 2 arguments and ignores the fact that second argument is vararg. Proof: if we remove "Object ... args" from IConsole.readLine, the test completes successfully.
Here is Workaround for this (hopefully temporary) problem: change the call to readLine to:
def testResult = consoleMock.readLine('testPrompt', [] as Object[])
then test completes successfully.
I also tried the same code against spock 1.0-groovy-2.0-SNAPSHOT - the problem is the same.
update-201312280030
The problem with varargs is solved! Many thanks to #charlesg, who answered my related question at: Spock: mock a method with varargs
The solution is the following: replace GroovyMock with Mock, then varargs are properly interpreted.

Exhaustively walking the AST tree in Groovy

This is related to my question on intercepting all accesses to a field in a given class, rather than just those done in a manner consistent with Groovy 'property' style accesses. You can view that here: intercepting LOCAL property access in groovy.
One way I've found that will definitely resolve my issue there is to use AST at compile time re-write any non-property accesses with property accesses. For example, a if a class looks like this:
class Foo {
def x = 1
def getter() {
x
}
def getProperty(String name) {
this."$name" ++
}
}
foo = new Foo()
assert foo.getter() == 1
assert foo.x == 2
These assert statements will work out because the getter method access x directly and the foo.x goes through getProperty("x") which increments x before returning.
After some trial and error I can use an AST transformation to change the behavior of the code such that the expression 'x' in the 'getter' method is actually accessed as a Property rather than as a local field. So far so good!
Now, how do I go about getting to ALL accesses of local fields in a given class? I've been combing the internet looking for an AST tree walker helper of some kind but haven't found one. Do I really need to implement an expression walker for all 38 expression types here http://groovy.codehaus.org/api/org/codehaus/groovy/ast/expr/package-summary.html and all 18 statement types here http://groovy.codehaus.org/api/org/codehaus/groovy/ast/stmt/package-summary.html? That seems like something that someone must have already written (since it would be integral to building an AST tree in the first place) but I can't seem to find it.
Glenn
You are looking for some sort of visitor. Groovy has a few (weakly documented) visitors defined that you could use. I don't have the exact answer for your problem, but I can provide you a few directions.
The snippet below shows how to transverse the AST of a class and print all method names:
class TypeSystemUsageVisitor extends ClassCodeVisitorSupport {
#Override
public void visitExpression(MethodNode node) {
super.visitMethod(node)
println node.name
}
#Override
protected SourceUnit getSourceUnit() {
// I don't know ho I should implement this, but it makes no difference
return null;
}
}
And this is how I am using the visitor defined above
def visitor = new TypeSystemUsageVisitor()
def sourceFile = new File("path/to/Class.groovy")
def ast = new AstBuilder().buildFromString(CompilePhase.CONVERSION, false, sourceFile.text).find { it.class == ClassNode.class }
ast.visitContents(visitor)
Visitors take care of transversing the tree for you. They have visit* methods that you can override and do whatever you want with them. I believe the appropriate visitor for your problem is CodeVisitorSupport, which has a visitVariableExpression method.
I recommend you to read the code of the AST Browser that comes along with groovyConsole for more examples on how to use Groovy AST Visitors. Also, take a look at the api doc for CodeVisitorSupport.

Resources