SoapUI defining a library of reusable methods - groovy

I'm running into copy-pasting a lot of code at the moment in my SoapUI projects, and thought I'd have some sort of library of helper functions that can carry out most of my tasks.
So I have a test suite for this, and the code itself is in a Groovy Script test step in this test suite. The idea is that I make my helper methods available to the context I'm in (a REST test request step).
It instantiates fine and all that, but the problem is that when I want to invoke run(testRunner, context), I am not having access to the testRunner property. I've read something about that this is how it is.
Anyone know a way around this?

I am using the same method as you for script library. I used the method described by Kerry Doan at http://www.doan.me/script-library-in-soapui-free.aspx
When i tried to access this script library from project load script i did not have access to the testRunner so i created the testRunner object and as i did not have access to the context object i had to create that too.
Check out the code below.
import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCaseRunner
import com.eviware.soapui.support.types.StringToObjectMap
import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext
//to create the testRunner object I need a testCase object and a new StringToObjectMap
//I initially used the test case in the script library but as i needed the
//testRunner object to the test case being executed so i created the object to
//the test case being executed.
//I did not want to worry about test suite or test case names so i used their index
//assuming that there will be at least one test suite and at least one test case when
//this script is run
testCase = project.getTestSuiteAt(0).getTestCaseAt(0)
tcRunner = new WsdlTestCaseRunner( testCase, new StringToObjectMap() );
//A context is essentially a WsdlTestRunContext object and as you can see below all i
//have done to create that is pass it a test step object which was obtained by using index
//rather than name.
tStep = testCase.getTestStepAt(0)
tcContext = new WsdlTestRunContext(tStep)
//my script library is in a seperate project called `Script Library` and all the
//groovy scripts are in a test suite called `Script Library`
scripts = project.workspace.projects["Script Library"].testSuites["Script Library"];
scripts.testCases["Scripts"].testSteps["runTest"].run(tcRunner, tcContext);

Related

How to share class object between groovy test steps?

I have an external groovy file containing all common functions required to automate my web service testing. I reference those common functions by creating an instance of the Class defined within the external file. Now I have a situation to create an instance of the Class in first groovy test step and to use the same instance in other groovy test steps within my test case.
import groovy.lang.Binding
import groovy.util.GroovyScriptEngine
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
// location of script file is relative to SOAPUI project file.
String scriptPath = groovyUtils.projectPath + "\\Scripts\\"
// Create Groovy Script Engine to run the script.
GroovyScriptEngine gse = new GroovyScriptEngine(scriptPath)
// Load the Groovy Script file
externalScript = gse.loadScriptByName("CustomerQuotes.groovy")
def cq = externalScript.newInstance(context: context, log: log, testRunner: testRunner)
How do I achieve this? I need the reference of cq object in other groovy test steps to call the remaining common functions available within my external grooy file? Please help.
As per your question, the mentioned groovy script test step is placed in an arbitrary test case though it is not a natural fit.
The natural fit for the above script is to use Load Script which is at project level.
In the script, which is mentioned in the question, change below statements
From:
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
// location of script file is relative to SOAPUI project file.
String scriptPath = groovyUtils.projectPath + "\\Scripts\\"
To:
def projectPath = new File(project.path).parent.toString()
String scriptPath = "${projectPath}/Scripts"
And keep the rest of the script same.
Place the script (after the above change) at Project level's Load Script.
Remove the groovy script test step from wherever it is because of the above mentioned reason.
At the end of the script, add the below statement. Basically using the groovy's Meta Programming feature to store the object for sharing.
project.metaClass.myObject = cq
Next step: How to re-use the object (which is the main question)?
Since, your object cq is added to project object, the same can be accessed in any of the groovy script test steps (at any suite or case) using below statement:
def cq = context.testCase.testSuite.project.myObject
//Now call the other methods using cq.method(arguments)
EDIT: It appears that the above solution works for simple/Primitive data types.
However, you have a class instance. For that some more changes are required.
Here is your complete Project level Load Script (includes your code snippet)
def projectPath = new File(project.path).parent.toString()
String scriptPath = "${projectPath}/Scripts"
GroovyScriptEngine gse = new GroovyScriptEngine(scriptPath)
def externalScript = gse.loadScriptByName("CustomerQuotes.groovy")
project.metaClass.myObject {
externalScript.newInstance(context: it, log: log, testRunner: it.testRunner)
}
And the script for Groovy Script test step in different test cases is as follows i.e., just calling the methods of your CustomerQuotes.groovy class.
def obj = context.testCase.testSuite.project.myObject(context)
obj.run()
Assuming that there is a method in the groovy file called run. Of course, you can use your own method.
EDIT 2:
There is another alternative approach too. You need to compile the groovy classes, create jar, copy it under SOAPUI_HOME/bin/ext directory. Of course, soapui tool needs to be restarted after that.
Now you can create instance and make the desired call to the methods as needed in any of the groovy script test steps.

Describe Mockito sample code

In the http://mockito.org/ website the following sample code is given to describe the usage of the mockito framework. However i am not able to understand what the following code is trying to test. Please comment on the following code as what is it exactly testing. If it is testing the add method of the List, what does it expect?
import static org.mockito.Mockito.*;
// mock creation
List mockedList = mock(List.class);
// using mock object - it does not throw any "unexpected interaction" exception
mockedList.add("one");
mockedList.clear();
// selective, explicit, highly readable verification
verify(mockedList).add("one");
verify(mockedList).clear();
In your case, you've a test preparation
// mock creation
List mockedList = mock(List.class);
a test execution
// using mock object - it does not throw any "unexpected interaction" exception
mockedList.add("one");
mockedList.clear();
and a test verification (without mockito mostly done with something like assertEquals)
// selective, explicit, highly readable verification
verify(mockedList).add("one");
verify(mockedList).clear();
The last block (the test verifaction) is testing, if
the add method of the mockedList was called with a parameter that equals the String "one"
the clear method of the mockedList was called
It is just a basic demo of how the interaction with a mocked class can be verified (since you cannot verify the contents of the List because it has been mocked and the calls of add("one") and clear() don't change the contents of the List).

Creating script library in SoapUI free version

I am new in SoapUI and groovy scripting
I would like to create a repository of groovy scripts that can be reused at various test steps
I am using SoapUI Free version and following is the structure of my SoapUI Project
Project
|-TestSuite
| |-TestCase
| |-TestSteps
| |-LocalScript (Groovy TestStep to reuse library scripts)
| |-OtherTestStep (Run TestCase TestStep)
|-ScriptLibrary
|-TestCase
|-TestSteps
|-GroovyScriptStep1 (Contain a class for commonly used functions)
|-GroovyScriptStep2 (Contain another class for other functions)
Here is what I was able to do:
I was able to create a library using the sample mentioned in this post. Similar to example in the post, my code in test step (GroovyScriptStep1 as per above structure) of library was just reading some value from external file and is used in test step of other TestSuite (LocalScript step in above structure).
Here is the problem:
Now I want to create a new class and add a function to it which will need info from running class and simply print it. The difference here is that some values are generated in the test run and should be passed to library script inorder to process/print etc.
To make my question more clear following is the code snippet
I will be using a simple scenario here
Sample objective: Want to be able to print all the assertions and status (since this will be used in all the test cases I want to create a library)
Code for same when not using library will be as under(this can go as groovy script step)
def obj = context.testCase.getTestStepByName("Request 1");
def assertions = obj.getAssertionList()
//Loop on assertions
assertions.each{
log.info(it.name + ' --> ' + it.status)
Code something similar in Library TestSuite's Test case step
context.setProperty("Assertions", new Assertions());
class Assertions{
def printAssertion(def someArgumentToGetAssertionlistforTestStepinAnotherTestSuite){
def obj = ????
def assertions = obj.getAssertionList()
//Loop on assertions
assertions.each{
log.info(it.name + ' --> ' + it.status)
}
}
}
Code from where I want to call this method (LocalScript as per above project structure)
scripts = testRunner.testCase.testSuite.project.testSuites["ScriptLibrary"];
scripts.testCases["Scripts"].testSteps["Assertions"].run(testRunner, context);
context.Assertions.printAssertion(ArgumentRequired);
This is just one example, I want to create libraries of some more common scripts that use context variable when used locally
Kindly help me with this and please let me know if some more information/clarification is required
What I get from your questions is that you want to create a code library in SoapUI that can be reused.
I think the best way is by creating jar files and deploying it in ext folder of SoapUI
Create a new groovy script file with a class (follows java standards in file naming i.e. class name and file name should be same)
Compile the groovy code file
Create the jar file
Deploy the jar file at SoapUI_Home/bin/ext folder
Restart the SoapUI if was already open
Create the object of class and use the methods anywhere in the SoapUI projects
Note: If you are migrating your project to some other machine, make sure to migrate these libraries as well if you are using them in projects
Details with example:
Step 1: Create a new groovy script file with a class structure
i. Considering the class ScriptLibrary that contain a method named printTestDetails as in following code in it:
class ScriptLibrary {
def context
def testRunner
def log
def printTestDetails(def PrintThisToo) {
log.info 'Name of the test case is :'+testRunner.testCase.name
log.info 'Name of the test suite is : '+testRunner.testCase.testSuite.name
log.info PrintThisToo
}
}
ii. Save the file with class name, ScriptLibrary.groovy in this case
Step 2: Compile the code
i. Open command prompt and fire following command (from the folder where where your .groovy file is kept)
Compile the code:
groovyc -d classes ScriptLibrary.groovy
Step 3: Create the jar file
i. After compiling the code we can create the jar
Create jar file:
jar cvf ScriptLibrary.jar -C classes .
Step 4: Deploy the jar file at SoapUI_Home/bin/ext folder
Step 5: Restart the SoapUI if was already open
Step 6: Create the object of class and use the methods anywhere in the SoapUI projects
i. Creating object
def scripts = new ScriptLibrary(context:context, log:log, testRunner:testRunner)
ii. Calling methods
scripts.printTestDetails(“This is my argument”)
I hope this solves your problem over all, this approach will allow you to freely use the code any where in the SoapUI and most importantly will solve your problem for getting context, log and testrunner in external code
You can also use any IDE of your choice to create code library and work on same to compile and create jar as well.
Let me know if you have any doubts or need more clarification
While I like Samarth's Answer for large projects, there is something about not having to leave SoapUI that makes TestHat's Answer very interesting.
This is what I used in my latest project:
A Testsuite ScriptLibrary with Testcases according to areas and Groovy script steps for every function.
I run these functions with testRunner.testCase.testSuite.project.testSuites["ScriptLibrary"].testCases["Demo"].testSteps["SomeFunction"].run(testRunner, context);, which then mutates the context to include the needed functions.
In order to use the correct log and testRunner instances, I pass those via parameters. e.g. context.someFunction(log, testRunner);
Because normal functions can't be assigned to the context, I either use closures or classes.
For classes I use something like
class SomeClass {
def logger;
def runner;
SomeClass(logger, runner) {
this.runner = runner;
this.logger = logger;
}
public static SomeClass with(logger, runner) {
return new SomeClass(logger, runner);
}
public void someFunction(String a) {
// This prints to the log of the caller function and not this one
logger.info a;
}
}
context.SomeClass = SomeClass;
and then call it with
testRunner.testCase.testSuite.project.testSuites["ScriptLibrary"].testCases["Demo"].testSteps["SomeClass"].run(testRunner, context);
context.SomeClass.with(log, testRunner).someFunction(
"Hello World"
);
This is mainly done because you can't easily create a new instance from the context.SomeClass variable.
While the context is persisted inside a Testcase, it gets cleared when using a "Run Testcase" teststep, which freqently use.
Maybe this was some help to somebody in the future.
This should do it
context.setProperty("Assertions", new Assertions());
class Assertions{
def printAssertion( tStep){
def assertions = tStep.getAssertionList()
//Loop on assertions
assertions.each{
log.info(it.name + ' --> ' + it.status)
}
}
}
and call it like this
TestStep=testRunner.testCase.testSuite.getTestCaseByName("yourTestCase").getTestStepByName("stepName")
context.Assertions.printAssertion(TestStep)
On the project level, you can write "Load Script" and you can save your utility class instance in the project level context:
context.setProperty("ScriptLibrary", new ScriptLibrary())
and in your test suit (eg. in "Setup Script") you can get it:
testSuite.project.context.getProperty('ScriptLibrary')
or in your test case:
testCase.testSuite.project.context.getProperty('ScriptLibrary')
or in your Groovy test step:
testRunner.testCase.testSuite.project.context.getProperty('ScriptLibrary')
For Assertion :
Put this script in Repository
context.setProperty("Assertions", new Assertions());
class Assertions{
def printAssertion(tStep){
def assertions = tStep.getAssertionList()
//Loop on assertions
}
}
Use this Script in SoapUI:
TestStep=testRunner.testCase.testSuite.getTestCaseByName("addTestCase").getTestStepByName("add")
//context.Assertions.printAssertion(TestStep)
scripts = testRunner.testCase.testSuite.project.testSuites["ScriptLibrary"];
scripts.testCases["Demo"].testSteps["TestAssertion"].run(testRunner, context);
context.Assertions.printAssertion(TestStep).each{
log.info(it.name + ' --> ' + it.status)
}
return null

SoapUI: Pass property values to called test case

I am a beginner in soapui testing. Hopefully you can help me solving this problem.
In my test project I have a test suites which contains several test cases. Multiple test case will start the same test case. To run this test case I need some property values to be transferred to this test case.
I tried to achieve this in two ways. But I failed in both.
I tried to call the test case and set the needed properties in the test case. I start the test case from a Groovy script. But I couldn't find a good example how to set the properties in the called test case.
I tried to get the property values of the calling parent test case inside the called test case. It looks like the parent test case that called the test case isn't available in the context of the running test case.
The test cases, that will call the same test case, will be run in parallel. So, I think it isn't a solution to first set the property values and then start the test case, because they will be overwritten by the other test cases that run at the same time. Also using test suite properties for these values won’t work because of running the test cases in parallel.
My test project looks like this.
MyProject
TestSuite_APLtests
TestCase_user_01
Properties test step
Run_test <groovy script>
Step_01
…..
TestCase_user_02
Properties test step
Run_test <groovy script>
Step_01
…..
TestCase_General
Properties test step
POST sessions
Step_01
…..
The ‘Properties test step’ of each ‘TestCase_user_’ contains a user and password needed in test case ‘TestCase_General’ and will be different for each test case.
In the ‘Run_test’ groovy script of each ‘TestCase_user_’ the test case ‘TestCase_General’ is started by using:
def myTestSuite = testRunner.testCase.testSuite.project.getTestSuiteByName("TestSuite_APLtests")
def myTestCase = myTestSuite.getTestCaseByName("TestCase_General")
myTestCase.run(null, false)
How can I add the properties user and password to the run comment that starts the test case?
If I try to get the property values with a groovy script in test case ‘TestCase_General’ I don’t know how to determine which test case has called ‘TestCase_General’. I found some posts on internet that suggests to use: context.getProperty("#CallingRunTestCaseStep#") to determine the calling test case. But this value is null. And when I try to check if the calling test case is available in the context by using: context.hasProperty("#CallingRunTestCaseStep#") this is false, so this doesn't work to find the calling test case.
Can someone tell me what the solution will be to get this working.
Thanks,
You can set Test Case properties from groovy script with setPropertyValue(name,value) method, however if you run the Test Cases in parallel, this properties as you said will be overwritten for each Test Case calling TestCase_General. So instead of use setPropertyValue you can pass the context properties through the run(StringToObjectMap properties, boolean async) method in the WsdlTestCase.java class. Your groovy code to call TestCase_General could be:
import com.eviware.soapui.support.types.StringToObjectMap
// get test suite
def myTestSuite = testRunner.testCase.testSuite.project.getTestSuiteByName("TestSuite_APLtests")
// get your test case
def myTestCase = myTestSuite.getTestCaseByName("TestCase_General")
// set the user and password properties in the context
context.setProperty("user","userTestCaseN")
context.setProperty("password","passwordTestCaseN")
// run the testCase passing the context
def contextMap = new StringToObjectMap( context )
myTestCase.run(contextMap,false);
To access the context properties in the groovy script of your TestCase_General use this code:
context.getProperty("userPassword")
Or if you prefer to use context.expand:
context.expand('${#user}')
Note that the use of # depends on how you are accessing the properties.
If you also need to use the context properties in the SOAP Test Request of your TestCase_General use this way ${#propetryName} i.e:
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Header/>
<Body>
<request>
<user>${#user}</user>
</request>
</Body>
</Envelope>
Hope this helps,

How to define a global class in SoapUI as a groovy script?

I want to define a class in a groovy script that i could reuse trough other groovy script inside SoapUI.
I alredy tried to define my class inside a TestSuite property but it doesn't work. I would like to avoid defining the class in a JAR because we work in team and every one would have to import the JAR in their SoapUI in order to run my tests. I use SoapUI 3.6.1
Here's how my TestSuite is made :
TestSuite
TestCase
TestSteps
Init (Groovy Script)
GetResponse1 (Test Request)
Test1 (Groovy Script)
GetResponse2 (Test Request)
Test2 (Groovy Script)
To simplify me tests, i defined a class in 'Test1' and i would like to reuse this class in 'Test2'. So ideally i would define that class in 'Init' and it would be accessible to any other groovy script.
How can i achieve that?
Based on #Abhey Rathore's link, here is how to define a global class in SoapUI's groovy script:
Step 1: Declare the global class
Create a project called MyRepository
Under this project create a disabled TestSuite called lib
Under this test suite create a TestCase called MyClass
Under this test case create a groovy script called class
Your project tree should look like the image below:
Step 2: Write the global class code
Inside the groovy script called class, copy and and paste the code below:
class MyClass {
// The three following fields are MANDATORY
def log
def context
def testRunner
// The constructor below is MANDATORY
def MyClass(logIn, contextIn, testRunnerIn) {
this.log = logIn
this.context = contextIn
this.testRunner = testRunnerIn
}
def myMethod() {
this.log.info 'Hello World!'
}
}
// Other scripts elsewhere in SoapUI will access the reused class through their context
context.setProperty( "MyClass", new MyClass(log, context, testRunner) )
Step 3: Import the global class
From any project, you can import the global class by using the following snippet:
// Import the class
def currentProject = testRunner.testCase.testSuite.project
currentProject
.testSuites["lib"]
.testCases["MyClass"]
.testSteps["class"]
.run(testRunner, context)
// Now use it
context.MyClass.myMethod()
SoapUI 5.2.1
try this, I think will help you in reusable code.
http://forum.soapui.org/viewtopic.php?t=15744
I am pretty sure that you will have to create a JAR file and put it in \bin\ext.
SoapUI will automatically pick it up on restart (you should see it mentioned in the startup stuff).
You basically just create a Java or Groovy project, Export it (with Eclipse) and it will work. SoapUI will probably have your dependencies covered, but if not you can add those JARs too (safer than creating a runnable JAR since SoapUI might use different versions of what you use).
If you need help, post related questions.
In SoapUI 5.3.0 you can use properties that can be set and get on the context variable. That variable is available in script assertion snippet.
For example:
context.setProperty("prop", "value");
And from different test script you can get the value by:
context.getProperty("prop");
You can use the property from when you define property as a step of test suite or as a value for field in header. You can do it by ${=context.getProperty("prop");}
Write this into your Project's load script, then reload your project or just run it.
com.eviware.soapui.support.ClasspathHacker.addFile( project.context.expand('${projectDir}') )
After it has run, you can now put .groovy files into the same folder as your soapui project xml. Plus, there is no need to compile anything.
e.g. in MyClass.groovy:
class MyClass {String name}
You can import those classes as normal in all your other scripts:
import MyClass
assert new MyClass(name:"me") instanceof MyClass
The only caveat is that your load script (the one setting the classpath), cannot have those imports, because the script will fail to compile. If you want to import something during your project load script, just have your load script 'evaluate' another groovy script (in other words, run it), in which you can use the imports:
evaluate (new File (project.context.expand('${projectDir}') + 'myProjectLoadScript.groovy'))
//in myProjectLoadScript.groovy:
import MyClass
/* Do things using MyClass... */
This seems the easiest way to me, so I'm not sure why I couldn't find this answer elsewhere online.

Resources