MartinSpamer
7 years agoFrequent Contributor
Let's talk Meta Programming to automatically refactor test cases in SOAPUI
One of SOAPUI's most powerful features and certainly my favourite is using Groovy for Meta-Programming to factor and enhace my tests. I thought I would share the latest meta-coding script I've added to my Reusable Script library .
This script can be used to enhance and cleanup a TestSuite that is created automatically using the built in feature Interface -> Generate TestSuite. I import quite a lot of my REST API and this approach saves me a lot of grunt work.
Script Features:
- Renames each RestReqest from "Request N" to something more appropiate following a basic BDD syntax using the HTTP Method and the resource description to provide appropriate description. e.g.
- "Request N" using a "HTTP GET /account"
- becomes "When /account is Retrieved"
- If the TestCase contains multiple requests these are split into new approriately named TestCases using the above convention to comply with the automated testing best practice of testing one thing at a time.
- Adds an Groovy script for Given and Then around each Request step in each TestCase.
To use this script.
- Define a Library TestSuite in the root of the project you want to refactor.
- Disable the Library TestSuite so that it doesn't get run in an uncontrolled manner.
- Define Meta-Programming Testcase to get this:
- Create a Groovy script in Meta-Programming and add the following code:
- Then simply run the Refactor Generate Tests.
refactorGeneratedTests(testRunner.testCase.testSuite.project)
cleanUp(testRunner.testCase.testSuite.project)
def refactorGeneratedTests(def thisProject) {
assert thisProject
log.info "Processing ${thisProject.name}"
for (testSuite in thisProject.testSuiteList) {
if (!testSuite.isDisabled()) {
log.info "- ${testSuite.name}"
for (testCase in testSuite.testCaseList) {
if (!testCase.isDisabled()) {
log.info "-- ${testCase.name}"
renameRequestSteps(testCase)
forEachRequestMake(testCase)
ensureBdd(testCase)
}
}
}
}
}
def renameRequestSteps(testCase) {
assert testCase
assert testCase instanceof WsdlTestCase
def languageMap = [ "GET": 'Retrieved', "POST": 'Created', "PUT": "Updated", 'DELETE': 'Deleted']
log.info "languageMap : ${languageMap}"
boolean isFirst = true
for (testStep in testCase.testStepList) {
log.info "--- ${testStep.name} ${testStep.getClass().getSimpleName()}"
if (isREST(testStep)) {
if (testStep.label.startsWith("Request")) {
String restOperation = testStep.getOperation().getName()
log.info "restOperation : " + restOperation
String methodType = testStep.getRestMethod().getMethod()
log.info "methodType : ${methodType}"
actionName = languageMap.get(methodType)
log.info "actionName : ${actionName}"
String newStepName = "When ${restOperation} is ${actionName}"
log.info "${newStepName}"
testStep.setName(newStepName)
}
}
}
}
def forEachRequestMake(testCase) {
assert testCase
assert testCase instanceof WsdlTestCase
def languageMap = [ "GET": 'Retrieve', "POST": 'Create', "PUT": "Update", 'DELETE': 'Delete']
log.info "languageMap : ${languageMap}"
boolean isFirst = true
for (testStep in testCase.testStepList) {
log.info "--- ${testStep.name} (${testStep.getClass().getSimpleName()})"
if (isREST(testStep)) {
String restOperation = testStep.getOperation().getName()
log.info "restOperation : " + restOperation
String methodType = testStep.getRestMethod().getMethod()
log.info "methodType : ${methodType}"
actionName = languageMap.get(methodType)
log.info "actionName : ${actionName}"
String newTestCaseName = "${actionName} ${restOperation} "
log.info "${newTestCaseName}"
if (isFirst) {
testCase.setName(newTestCaseName)
isFirst = false
} else {
// clone the test for each REST request
testCase.testSuite.cloneTestCase(testCase, newTestCaseName);
}
}
}
}
def ensureBdd(testCase) {
assert testCase
assert testCase instanceof WsdlTestCase
givenStep = "Given content for the request"
if (testCase.getTestStepByName(givenStep) == null) {
testCase.insertTestStep("groovy", givenStep, 0)
}
thenStep = "Then the response is as expected"
if (testCase.getTestStepByName(thenStep) == null) {
testCase.addTestStep("groovy", thenStep)
}
}
def isREST(def testStep) {
assert testStep
return testStep instanceof RestTestRequestStep;
}
def addHttpStatusAssertions(testStep) {
assert testStep
return testStep instanceof RestTestRequestStep;
if (testStep.getAssertionCount() == 0) {
testStep.addAssertion("Valid HTTP Status Codes").setCodes("200")
testStep.addAssertion("Invalid HTTP Status Codes").setCodes("400, 500")
}
log.info testStep.getAssertionList()
}
def cleanUp(def thisProject) {
assert thisProject
log.info "${thisProject.name}"
for (testSuite in thisProject.testSuiteList) {
log.info "- ${testSuite.name}"
for (testCase in testSuite.testCaseList) {
log.info "-- ${testCase.name}"
String actionName = testCase.name.split().head()
log.info "-- ${actionName}"
for (testStep in testCase.testStepList) {
log.info "--- ${testStep.name} ${testStep.getClass().getSimpleName()}"
if (isREST(testStep)) {
if (testStep.name.contains(actionName)) {
log.info("keep ${testStep.name} in ${testCase.name}")
} else {
log.info("remove ${testStep.name} from ${testCase.name}")
testCase.removeTestStep(testStep)
}
}
}
}
}
}
// https://www.soapui.org/apidocs/com/eviware/soapui/impl/wsdl/teststeps/RestTestRequestStep.html
// class com.eviware.soapui.impl.wsdl.WsdlProject
// class com.eviware.soapui.impl.wsdl.WsdlTestSuite
// class com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase
// class com.eviware.soapui.impl.wsdl.teststeps.WsdlGroovyScriptTestStep
log.info context.getClass()
log.info testRunner.getClass()
log.info testRunner.testCase.getClass()
log.info testRunner.testCase.testSuite.getClass()
log.info testRunner.testCase.testSuite.project.getClass()
log.info testRunner.testCase.testSuite.project.workspace.getClass()
import com.eviware.soapui.impl.wsdl.WsdlTestSuite
import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase
import com.eviware.soapui.impl.wsdl.teststeps.RestTestRequestStep