Creating a Test Report from Project level tear down script - groovy

I have generate a report based on an execution of a test suite where it creates a folder directory and insert a file displaying the report. This is compiled within a TearDown Script at Test Suite level. Below is the code:
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
def dataFolder = groovyUtils.projectPath
def failedTestCases = 0
def succeedTestCases = 0
def totalTestCases = 0
def testCaseFailed = ""
def testCaseSucceed = ""
def date = new Date()
def folderTime = date.format("yyyy-MM-dd HH-mm-ss")
def hotelId = context.getProperty('hotelid')
def hotelname = context.getProperty('hotelname')
def hoteltype = context.getProperty('hoteltype')
//def propertyValues = ""
//def correlationid = messageExchange.modelItem.testStep.testCase.testSuite.Project.namegetPropertyValue("correlationid")
//Create a folder directory for the responses
RootResultFolder = dataFolder + "\\Test Reports" + "\\xxx_WebAPI - " + folderTime + "\\"
CreateResultFolder = new File(RootResultFolder)
CreateResultFolder.mkdir()
//context.setProperty("RootResultFolder", RootResultFolder)
def fileName = "WebAPI Test Report.txt"
def rootFolder = RootResultFolder + fileName
def logFile = new File(rootFolder)
if(logFile.exists())
{
log.info("Error a file named " + fileName + "already exisits")
}
else
{
runner.results.each { testCaseResult ->
def name = testCaseResult.testCase.name
totalTestCases++
if(testCaseResult.status.toString() == 'FAILED'){
failedTestCases ++
testCaseFailed += "- $name - HAS FAILED \n\n"
//propertyValues += "hotelid - $hotelid, hotelname - $hotelname, hoteltype - $hoteltype \n\n"
testCaseResult.results.each{ testStepResults ->
testStepResults.messages.each() { msg -> log.info msg }
}
}else{
succeedTestCases ++
testCaseSucceed += "- $name - SUCCEED \n\n"
testCaseResult.results.each{ testStepResults ->
testStepResults.messages.each() { msg -> log.info msg }
}
}
}
}
logFile.write "TOTAL TEST CASES SUCCEED: $succeedTestCases of $totalTestCases" + "\n\n" +
testCaseSucceed + "---\n\n" +
"TOTAL TEST CASES FAILED: $failedTestCases of $totalTestCases" + "\n\n" +
testCaseFailed + "\n\n"
What I actually want to do is move the code from Test Suite level and place it in the tear down script at Project level. Now when I run the code from there, it does not generate the file, I'm assuming I need to place the correct paths in as I am not moving to test suite to test case but from project to test suite to testcase to test steps.
My question is really on syntax, I want to develop a report when the whole project is run, it outputs the following results:
Project Name - is it success or failed. If one suite failed then project fails else it passes
Test Suite - Take name of each test suite in project and if passes then place 'Succeed' next to name of test suite else place 'Failed' next to name of test suite
Name of all test cases within test suite. Like the one in screenshot really, 'succeed' next to test cases that have passed and 'failed' next to those that haven't.
Finally the property values. If a test case has failed, capture the property values for that failed test case so we can track which values were entered that caused the failure of the test.
Can somebody help me with the relevant syntax to perform these so then I can peice it into my code and manipulate?
UPDATE:
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
def dataFolder = groovyUtils.projectPath
def date = new Date()
def folderTime = date.format("yyyy-MM-dd HH-mm-ss")
//Create a folder directory for the responses
RootResultFolder = dataFolder + "\\Test Reports" + "\\xxx - " + folderTime + "\\"
CreateResultFolder = new File(RootResultFolder)
CreateResultFolder.mkdir()*/
//context.setProperty("RootResultFolder", RootResultFolder)
def reportFileName = "WebAPI Test Report.txt"
def rootFolder = RootResultFolder + reportFileName
def logFile = new File(rootFolder)

If you look at the TearDown Script of the project, it shows as below i.e., the variables already initialized by soapui.
Issue with your script
So if you look at it, there is runner variable. Also the same variable is available at TearDown script of test suite level. But, these are instances of different Objects. The script used in OP was of suite level which you aware and that is why you are not seeing in the result.
Here is the project level TearDown Script and following in line comments.
/**
*
* Below is the TearDown script for SoapUI Project level
* Which create a custom report in a given file
* Modify the variable "reportFileName" below
*
**/
//Modify the file as needed for report file
//def reportFileName = '/tmp/abctestreport.txt'
//Adding the below as user wants specific directory
//Get the project path
def dataFolder = new com.eviware.soapui.support.GroovyUtils(context).projectPath
//Create today's date for storing response
def today = new Date().format("yyyy-MM-dd")
def filePrefix = "${dataFolder}/TestReports/xxx_WebAPI_${today}" as String
def fileNamePart = new Date().format("yyyy-MM-dd'T'HH.mm.ss")
//creating filename dynamically.
def reportFileName = "${filePrefix}/xxx_WebAPI_TestReport_${fileNamePart}.txt" as String
//NOTE: Not required to edit beyond this point
/**
* This class holds the test case details
**/
class TestCaseResultHolder {
def log
Map<String, String> properties = [:]
boolean status
def createProperties(testCase) {
testCase.getPropertyNames().each { key ->
properties[key] = testCase.getPropertyValue(key)
}
}
def getCaseResult(caseRunner, caseName) {
log.info "Checking test case status ${caseName}"
if ( caseRunner.status.toString() == 'FAILED' ){
log.error "Test case $caseName has failed"
for ( stepResult in caseRunner?.results ){
stepResult.messages.each() { msg -> log.info msg }
}
return false
} else {
log.info "${caseName} is passed"
}
true
}
def buildCaseResult(caseRunner, caseName) {
status = getCaseResult(caseRunner, caseName)
if (!status) {
createProperties(caseRunner.testCase)
}
}
}
/**
* This class holds the test suite details
**/
class SuiteResultsHolder {
def log
Map<String, TestCaseResultHolder> casaeResults = [:]
int testCaseCount = 0
int passedCasesCount = 0
int failedCasesCount = 0
def buildSuiteResults(suiteRunner, suiteName){
log.info "Building results of test suite ${suiteName}"
for ( caseRunner in suiteRunner?.results ) {
def caseName = caseRunner.testCase.name
testCaseCount++
def tcHolder = new TestCaseResultHolder(log: log)
tcHolder.buildCaseResult(caseRunner, caseName)
casaeResults[caseName] = tcHolder
if (tcHolder.status) {
passedCasesCount++
} else {
failedCasesCount++
}
}
}
def getStatus() {
(0 < failedCasesCount) ? false : true
}
}
/**
* This class holds the project details
**/
class ProjectResultsHolder {
def log
Map<String, SuiteResultsHolder> suiteResults = [:]
int suiteCount = 0
int passedSuitecount = 0
int failedSuiteCount = 0
def buildProjectResults(projectRunner, projectName) {
log.info "Building results of test project ${projectName}"
for(suiteRunner in projectRunner?.results) {
def suiteName = suiteRunner.testSuite.name
suiteCount++
def suiteResultsHolder = new SuiteResultsHolder(log: log)
suiteResultsHolder.buildSuiteResults(suiteRunner, suiteName)
suiteResults[suiteName] = suiteResultsHolder
if (suiteResultsHolder.status) {
passedSuitecount++
} else {
failedSuiteCount++
}
}
}
def getStatus() {
(0 < failedSuiteCount) ? false : true
}
}
//Get the status string based on boolean
def getResult(status){ status == true ? 'SUCCEED' : 'FAILED'}
//Draws a line
def drawLine(def letter = '=', def count = 70) { letter.multiply(count)}
//Gets the summary report
def getSummaryReport(project, projectResultHolder) {
def report = new StringBuffer()
report.append(drawLine()).append('\n')
report.append("\t\t\tTest Execution Summary\n")
report.append(drawLine('-', 60)).append('\n')
report.append("Project : ${project.name}\n")
report.append("Result : ${getResult(projectResultHolder.status)}\n")
report.append("Total test suites executed: ${projectResultHolder.suiteCount}\n")
report.append("Test suites passed: ${projectResultHolder.passedSuitecount}\n")
report.append("Test suites failed: ${projectResultHolder.failedSuiteCount}\n")
report.append(drawLine()).append('\n')
report
}
//Gets the test case report
def getTestCaseReport(testCaseReport) {
def report = new StringBuffer()
report.append(drawLine('-', 60)).append('\n')
report.append("\t\tTest Case Details:\n")
report.append(drawLine('-', 60)).append('\n')
testCaseReport.each { kase, tcReport ->
report.append("Name : ${kase}\n")
report.append("Status : ${getResult(tcReport.status)}\n")
if (!tcReport.status) {
report.append("Properties : ${tcReport.properties.toString()}\n")
}
}
report
}
//Get the detailed report
def getDetailedReport(projectResultHolder) {
def report = new StringBuffer()
report.append(drawLine()).append('\n')
report.append("\t\t\tTest Execution Detailed Report\n")
report.append(drawLine()).append('\n')
projectResultHolder.suiteResults.each { suite, details ->
report.append("Test Suite : ${suite}\n")
report.append("Result : ${getResult(details.status)}\n")
report.append("Total Cases : ${details.testCaseCount}\n")
report.append("Cases Passed : ${details.passedCasesCount}\n")
report.append("Cases Failed: ${details.failedCasesCount}\n")
report.append(getTestCaseReport(details.casaeResults))
report.append(drawLine()).append('\n')
report.append(drawLine()).append('\n')
}
report
}
//Save the contents to a file
def saveToFile(file, content) {
if (!file.parentFile.exists()) {
file.parentFile.mkdirs()
log.info "Directory did not exist, created"
}
file.write(content)
assert file.exists(), "${file.name} not created"
}
def holder = new ProjectResultsHolder(log: log)
holder.buildProjectResults(runner, project.name)
def finalReport = new StringBuffer()
finalReport.append(getSummaryReport(project, holder))
finalReport.append(getDetailedReport(holder))
def reportFile = new File(reportFileName)
saveToFile(reportFile, finalReport.toString())
And here is the generated output:

Related

Finding a String from list in a String is not efficient enough

def errorList = readFile WORKSPACE + "/list.txt"
def knownErrorListbyLine = errorList.readLines()
def build_log = new URL (Build_Log_URL).getText()
def found_errors = null
for(knownError in knownErrorListbyLine) {
if (build_log.contains(knownError)) {
found_errors = build_log.readLines().findAll{ it.contains(knownError) }
for(error in found_errors) {
println "FOUND ERROR: " + error
}
}
}
I wrote this code to find listed errors in a string, but it takes about 20 seconds.
How can I improve the performance? I would love to learn from this.
Thanks a lot!
list.txt contains a string per line:
Step ... was FAILED
[ERROR] Pod-domainrouter call failed
#type":"ErrorExtender
[postDeploymentSteps] ... does not exist.
etc...
And build logs is where I need to find these errors.
Try this:
def errorList = readFile WORKSPACE + "/list.txt"
def knownErrorListbyLine = errorList.readLines()
def build_log = new URL (Build_Log_URL)
def found_errors = null
for(knownError in knownErrorListbyLine) {
build_log.eachLine{
if ( it.contains(knownError) ) {
println "FOUND ERROR: " + error
}
}
}
This might be even more performant:
def errorList = readFile WORKSPACE + "/list.txt"
def knownErrorListbyLine = errorList.readLines()
def build_log = new URL (Build_Log_URL)
def found_errors = null
build_log.eachLine{
for(knownError in knownErrorListbyLine) {
if ( it.contains(knownError) ) {
println "FOUND ERROR: " + error
}
}
}
Attempt using the last one relying on string eachLine instead.
def errorList = readFile WORKSPACE + "/list.txt"
def knownErrorListbyLine = errorList.readLines()
def build_log = new URL (Build_Log_URL).getText()
def found_errors = null
build_log.eachLine{
for(knownError in knownErrorListbyLine) {
if ( it.contains(knownError) ) {
println "FOUND ERROR: " + error
}
}
}
Try to move build_log.readLines() to the variable outside of the loop.
def errorList = readFile WORKSPACE + "/list.txt"
def knownErrorListbyLine = errorList.readLines()
def build_log = new URL (Build_Log_URL).getText()
def found_errors = null
def buildLogByLine = build_log.readLines()
for(knownError in knownErrorListbyLine) {
if (build_log.contains(knownError)) {
found_errors = buildLogByLine.findAll{ it.contains(knownError) }
for(error in found_errors) {
println "FOUND ERROR: " + error
}
}
}
Update: using multiple threads
Note: this may help in case errorList size is large enough. And also if the matching errors distributed evenly.
def sublists = knownErrorListbyLine.collate(x)
// int x - the sublist size,
// depends on the knownErrorListbyLine size, set the value to get e. g. 4 sublists (threads).
// Also do not use more than 2 threads per CPU. Start from 1 thread per CPU.
def logsWithErrors = []// list for store results per thread
def lock = new Object()
def threads = sublists.collect { errorSublist ->
Thread.start {
def logs = build_log.readLines()
errorSublist.findAll { build_log.contains(it) }.each { error ->
def results = logs.findAll { it.contains(error) }
synchronized(lock) {
logsWithErrors << results
}
}
}
}
threads*.join() // wait for all threads to finish
logsWithErrors.flatten().each {
println "FOUND ERROR: $it"
}
Also, as was suggested earlier by other user, try to measure the logs download time, it could be the bottleneck:
def errorList = readFile WORKSPACE + "/list.txt"
def knownErrorListbyLine = errorList.readLines()
def start = Calendar.getInstance().timeInMillis
def build_log = new URL(Build_Log_URL).getText()
def end = Calendar.getInstance().timeInMillis
println "Logs download time: ${(end-start)/1000} ms"
def found_errors = null

Groovy throws MissingPropertyException when calling getter method

I'm writing a small Groovy script for Hybris.
For reasons unknown when I attempt to call .getCronExpression() Groovy tries to get a property named getCron.
Script execution has failed [reason: groovy.lang.MissingPropertyException: No such property: getCron for class: de.hybris.platform.cronjob.model.TriggerModel]
The getter which I try to call exists on the class.
def methods = TriggerModel.declaredMethods.findAll { !it.synthetic }.name
println methods;
//[getDaysOfWeek, getWeekInterval, setDaysOfWeek, setWeekInterval, getRelative, getJob, setActivationTime, setMaxAcceptableDelay, getTimeTable, setActive, setJob, getCronJob, getActivationTime, setDateRange, getDateRange, getMaxAcceptableDelay, getCronExpression, setCronExpression, setCronJob, getActive, setRelative, setDay, setHour, setMinute, setSecond, getHour, getMinute, getSecond, getYear, getMonth, setYear, setMonth, getDay]
Code part:
def currentDate = new Date();
def query = new FlexibleSearchQuery("SELECT {pk} FROM {cronjob} WHERE {active} IS true");
def result = flexibleSearchService.search(query).getResult();
for (cj in result) {
def activeTriggers = cj.getTriggers().stream().filter{p -> p.getActive()}.collect();
if (activeTriggers){
def at = activeTriggers.get(0);
def activationTS = at.getActivationTime(); // works
if (activationTS.before(currentDate)){
println cj.code + " has invalid next activation date set: " + activationTS;
}
def x = at.getCronExpression(); // error
}
Update: the project uses hybris 5.7
Replacing the getter with the variable name fixed the issue.
Replace-
def x = at.getCronExpression(); // error
with
def xam = at.cronExpression; // working
Complete working groovy-
import de.hybris.platform.servicelayer.search.FlexibleSearchQuery;
def currentDate = new Date();
def query = new FlexibleSearchQuery("SELECT {pk} FROM {cronjob} WHERE {active}='1'");
def result = flexibleSearchService.search(query).getResult();
for (cj in result) {
def activeTriggers = cj.getTriggers().stream().filter{p -> p.getActive()}.collect();
if (activeTriggers){
def at = activeTriggers.get(0);
def activationTS = at.getActivationTime(); // works
if (activationTS.before(currentDate)){
println cj.code + " has invalid next activation date set: " + activationTS;
}
def xam = at.cronExpression; // working
}
}
Can you share your groovy part where you are loading activeTriggers?
I created a sample groovy to load Triggers and print CronExpression for 1st object and it worked like a charm.
import de.hybris.platform.servicelayer.search.FlexibleSearchQuery;
flexibleQuery = new FlexibleSearchQuery("select {pk} from {Trigger}");
flexibleSearchService = spring.getBean("flexibleSearchService")
activeTriggers = flexibleSearchService.search(flexibleQuery).getResult();
def at = activeTriggers.get(0);
def x = at.getCronExpression();
OUTPUT
0 0 0/4 * * ? *
AFTER PO EDITED THE QUESTION I still don't see getCronExpression error, I believe you were calling the function on a different object then TriggerModel. Though there were some syntax errors in your groovy, a working version of the copy is as below. (Tested on 1905 version)
import de.hybris.platform.servicelayer.search.FlexibleSearchQuery;
def currentDate = new Date();
def query = new FlexibleSearchQuery("SELECT {pk} FROM {cronjob} WHERE {active} = true");
def result = flexibleSearchService.search(query).getResult();
for (cj in result) {
def activeTriggers = cj.getTriggers().stream().filter{p -> p.getActive()}.collect();
if (activeTriggers){
def at = activeTriggers.get(0);
def activationTS = at.getActivationTime(); // works
if (activationTS!=null && activationTS.before(currentDate)){
println cj.code + " has invalid next activation date set: " + activationTS;
}
def x = at.getCronExpression(); // error
println x;
}
}

How to Get all total test case counts and status from project tear down script

Below is the tear down script to get the all test case counts and status from suite tear down but i need to get the overall test suite counts and status from project tear down but unfortunately it will not support the object of test runner class.
def failedTestCases = 0
runner.results.each { testCaseResult ->
def name = testCaseResult.testCase.name
if(testCaseResult.status.toString() == 'FAILED') {
failedTestCases++
log.info "$name has failed"
testCaseResult.results.each { testStepResults ->
testStepResults.messages.each { msg -> log.info msg }
}
} else {
log.info "$name works correctly"
}
}
On your project, create a Setup Script:
project.setPropertyValue("testcasesRun","0")
project.setPropertyValue("testcasesFailed","0")
On each of your TestSuites, create a TearDown Script something along this:
def failedTestCases = 0
def testCasesRun = 0
runner.results.each { testCaseResult ->
testCasesRun++
if(testCaseResult.status == com.eviware.soapui.model.testsuite.TestRunner.Status.FAILED) {
failedTestCases++
}
}
def existingFailedTestCases = new Integer( runner.testSuite.project.getPropertyValue("testcasesFailed") )
def newFailedValue = existingFailedTestCases + failedTestCases
runner.testSuite.project.setPropertyValue("testcasesFailed",newFailedValue.toString())
def existingRunTestCases = new Integer( runner.testSuite.project.getPropertyValue("testcasesRun") )
def newRunTestCases = existingRunTestCases + testCasesRun
runner.testSuite.project.setPropertyValue("testcasesRun",newRunTestCases.toString())
After running the project, you should have two Project Properties, holding number of counted testcases and failed testcases.

How to run SoapUI teststeps in parrallel with Groovy

SoapUI has options to run your test-suites and test-cases in parallel but no such thing for doing it with test-steps.
How can I achieve such a thing with a Groovy teststep inside my testcase?
This is my current code:
import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCaseRunner
//Get all Soap type test steps within the testCases
for ( testStep in testRunner.testCase.getTestStepsOfType(com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep.class)){
//Print out the name for the testStep
tsname = testStep.getName();
log.info tsname;
//thread = new Thread("$tsname")
def th = new Thread("$tsname") {
#Override
public void run(){
//Set the TestRunner to the respective TestCase
TestRunner = new com.eviware.soapui.impl.wsdl.testcase.WsdlTestCaseRunner(testRunner.testCase, null);
//Run them all and then rejoin the threads
log.info("thread: " + tsname)
TestRunner.runTestStepByName(tsname);
def soapResponse = TestRunner.getTestCase().getTestStepByName(tsname).getProperty("Response");
log.info "soapResponse: " + soapResponse;
th.join();
}
}
th.start();
th.join();
}
Managed to fix it myself and posted the answer here for all who stumble into the same problem:
import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep
List<String> steps = testRunner.testCase.getTestStepsOfType(com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep.class)
def map = [:]
//define the threads list, this will hold all threads
def threads = []
def kickEm = steps.each{ step ->
def th = new Thread({
stepName = step.getName();
log.info "Thread in start: " + step.getName();
//Set the TestRunner to the respective TestCase
TestRunner = new com.eviware.soapui.impl.wsdl.testcase.WsdlTestCaseRunner(testRunner.testCase, null);
//Run the corresponding teststep
TestRunner.runTestStepByName(step.getName());
//Get the response of the current step
def soapResponse = context.expand(TestRunner.getTestCase().getTestStepByName(step.getName()).getPropertyValue('Response')) as String;
log.info "In thread "+step.getName()+" soapResponse: " + soapResponse
//Put this into a map, the key is the stepname and the value is its response, so we can retrieve it all outside the each loop
map.put(step.getName(), soapResponse);
})
log.info "Putting new Thread({..}) th back into the threads list";
threads << th;
}
threads.each { it.start(); }
threads.each { it.join(); }
log.info "Map: "
map.each { step, response ->
log.info "Step: ${step} has the response ${response}"
};
log.info "Done!"

Creating a Test Report in SoapUI from Project level tear down script

I tried to change the code that #Rao wrote, here's a link! to show the details of the Test Steps in the report, unfortunately it does not work. Could someone help?
My question is really on syntax, I want to develop a report when the whole project is run, it outputs the following results:
Project Name - is it success or failed. If one suite failed then project fails else it passes
Test Suite - Take name of each test suite in project and if passes then place 'Succeed' next to name of test suite else place 'Failed' next to name of test suite
Name of all test cases within test suite. Like the one in screenshot really, 'succeed' next to test cases that have passed and 'failed' next to those that haven't.
Test Step- Take name of each test step in project and if passes then place 'Succeed' next to name of test step else place 'Failed' next to name of test step
Finally the property values. If a test case has failed, capture the property values for that failed test case so we can track which values were entered that caused the failure of the test
Below is the code:
/**
*
* Below is the TearDown script for SoapUI Project level
* Which create a custom report in a given file
* Modify the variable "reportFileName" below
*
**/
//Modify the file as needed for report file
//def reportFileName = '/tmp/abctestreport.txt'
//Adding the below as user wants specific directory
//Get the project path
def dataFolder = new com.eviware.soapui.support.GroovyUtils(context).projectPath
//Create today's date for storing response
def today = new Date().format("yyyy-MM-dd")
def filePrefix = "${dataFolder}/TestReports/Local_AllModules_Report_${today}" as String
def fileNamePart = new Date().format("yyyy-MM-dd'T'HH.mm.ss")
//creating filename dynamically.
def reportFileName = "${filePrefix}/Local_AllModules_TestReport_${fileNamePart}.txt" as String
//NOTE: Not required to edit beyond this point
/**
* This class holds the test step details
**/
class TestStepResultHolder {
def log
Map<String, String> propertiesTest = [:]
boolean status
def getTestStepList(testCase) {
testCase.getTestCase().each { key ->
propertiesTest[key] = testCase.getTestStepByName(key)
}
}
def getStepResult(stepRunner, stepName) {
log.info "Checking test case status ${stepName}"
if ( stepRunner.status.toString() == 'FAILED' ){
log.error "Test case $stepName has failed"
for ( step_Result in stepRunner?.results ){
step_Result.messages.each() { msg -> log.info msg }
}
return false
} else {
log.info "${stepName} is passed"
}
true
}
def buildStepResult(stepRunner, stepName) {
status = getStepResult(stepRunner, stepName)
if (!status) {
createProperties(stepRunner.testCase)
}
}
}
/**
* This class holds the test case details
**/
class TestCaseResultHolder {
def log
Map<String, String> properties = [:]
boolean status
def createProperties(testCase) {
testCase.getPropertyNames().each { key ->
properties[key] = testCase.getPropertyValue(key)
}
}
def getCaseResult(caseRunner, caseName) {
log.info "Checking test case status ${caseName}"
if ( caseRunner.status.toString() == 'FAILED' ){
log.error "Test case $caseName has failed"
for ( stepResult in caseRunner?.results ){
stepResult.messages.each() { msg -> log.info msg }
}
return false
} else {
log.info "${caseName} is passed"
}
true
}
def buildCaseResult(caseRunner, caseName) {
status = getCaseResult(caseRunner, caseName)
if (!status) {
createProperties(caseRunner.testCase)
}
}
}
/**
* This class holds the test suite details
**/
class SuiteResultsHolder {
def log
Map<String, TestCaseResultHolder> casaeResults = [:]
int testCaseCount = 0
int passedCasesCount = 0
int failedCasesCount = 0
def buildSuiteResults(suiteRunner, suiteName){
log.info "Building results of test suite ${suiteName}"
for ( caseRunner in suiteRunner?.results ) {
def caseName = caseRunner.testCase.name
testCaseCount++
def tcHolder = new TestCaseResultHolder(log: log)
tcHolder.buildCaseResult(caseRunner, caseName)
casaeResults[caseName] = tcHolder
if (tcHolder.status) {
passedCasesCount++
} else {
failedCasesCount++
}
}
}
def getStatus() {
(0 < failedCasesCount) ? false : true
}
}
/**
* This class holds the project details
**/
class ProjectResultsHolder {
def log
Map<String, SuiteResultsHolder> suiteResults = [:]
int suiteCount = 0
int passedSuitecount = 0
int failedSuiteCount = 0
def buildProjectResults(projectRunner, projectName) {
log.info "Building results of test project ${projectName}"
for(suiteRunner in projectRunner?.results) {
def suiteName = suiteRunner.testSuite.name
suiteCount++
def suiteResultsHolder = new SuiteResultsHolder(log: log)
suiteResultsHolder.buildSuiteResults(suiteRunner, suiteName)
suiteResults[suiteName] = suiteResultsHolder
if (suiteResultsHolder.status) {
passedSuitecount++
} else {
failedSuiteCount++
}
}
}
def getStatus() {
(0 < failedSuiteCount) ? false : true
}
}
//Get the status string based on boolean
def getResult(status){ status == true ? 'SUCCEED' : 'FAILED'}
//Draws a line
def drawLine(def letter = '=', def count = 70) { letter.multiply(count)}
//Gets the summary report
def getSummaryReport(project, projectResultHolder) {
def report = new StringBuffer()
report.append(drawLine()).append('\n')
report.append("\t\t\tTest Execution Summary\n")
report.append(drawLine('-', 60)).append('\n')
report.append("Project : ${project.name}\n")
report.append("Result : ${getResult(projectResultHolder.status)}\n")
report.append("Total test suites executed: ${projectResultHolder.suiteCount}\n")
report.append("Test suites passed: ${projectResultHolder.passedSuitecount}\n")
report.append("Test suites failed: ${projectResultHolder.failedSuiteCount}\n")
report.append(drawLine()).append('\n')
report
}
//Gets the test case report
def getTestCaseReport(testCaseReport) {
def report = new StringBuffer()
report.append(drawLine('-', 60)).append('\n')
report.append("\t\tTest Case Details:\n")
report.append(drawLine('-', 60)).append('\n')
testCaseReport.each { kase, tcReport ->
report.append("Name : ${kase}\n")
report.append("Status : ${getResult(tcReport.status)}\n")
if (!tcReport.status) {
report.append("Properties : ${tcReport.properties.toString()}\n")
}
}
report
}
//Gets the test step report
def getTestStepReport(testStepReport) {
def report = new StringBuffer()
report.append(drawLine('-', 60)).append('\n')
report.append("\t\tTest Case Details:\n")
report.append(drawLine('-', 60)).append('\n')
testStepReport.each { kaset, tsReport ->
report.append("Name : ${kaset}\n")
report.append("Status : ${getResult(tsReport.status)}\n")
if (!tsReport.status) {
report.append("Properties : ${tsReport.propertiesTest.toString()}\n")
}
}
report
}
//Get the detailed report
def getDetailedReport(projectResultHolder) {
def report = new StringBuffer()
report.append(drawLine()).append('\n')
report.append("\t\t\tTest Execution Detailed Report\n")
report.append(drawLine()).append('\n')
projectResultHolder.suiteResults.each { suite, details ->
report.append("Test Suite : ${suite}\n")
report.append("Result : ${getResult(details.status)}\n")
report.append("Total Cases : ${details.testCaseCount}\n")
report.append("Cases Passed : ${details.passedCasesCount}\n")
report.append("Cases Failed: ${details.failedCasesCount}\n")
report.append(getTestCaseReport(details.casaeResults))
report.append(drawLine()).append('\n')
report.append(drawLine()).append('\n')
}
report
}
//Save the contents to a file
def saveToFile(file, content) {
if (!file.parentFile.exists()) {
file.parentFile.mkdirs()
log.info "Directory did not exist, created"
}
file.write(content)
assert file.exists(), "${file.name} not created"
}
def holder = new ProjectResultsHolder(log: log)
holder.buildProjectResults(runner, project.name)
def finalReport = new StringBuffer()
finalReport.append(getSummaryReport(project, holder))
finalReport.append(getDetailedReport(holder))
def reportFile = new File(reportFileName)
saveToFile(reportFile, finalReport.toString())
To get test step result you may add a script like the one I use in your testcase's teardown script:
log.info "nb steps : " + testRunner.getTestCase().getTestStepCount()
for (testStep in testRunner.getResults()){
log.info "step " + testStep.getTestStep().getName() + " : " + testStep.getStatus()
}
You can also add the following in the testsuite's teardown script but when you run at testsuite level you will not get testcase's teardown scripts:
log.info "*********** EXECUTION SUMMARY *****************************************"
def runner = context.testRunner;
//log.info "nb test results = " + runner.getResultCount()
for (testRun in runner.getResults())
{
testCase = testRun.getTestCase()
//log.info "testCase " + testCase
log.info context.expand( '${#Project#testcase_flag}' ) + testCase.getName()
log.info "nb test steps = "+ testCase.getTestStepCount()
for (testResult in testRun.getResults())
log.info testResult.getTestStep().getName() + " : " + testResult.getStatus()
log.info context.expand( '${#Project#testcase_status_flag}' ) + " : " + runner.getStatus()
}
log.info "*************************************************************************************"
This works pretty well for me ...

Resources