Parse a JSON Response Using Groovy
Symptoms Quite often we need to parse a JSON response to get some value or to compare the received value with the target one.This code can be copied directly into a Groovy Script test step and run to demonstrate a few ways to get data from a JSON REST response Solution // Some Examples of How to Parse a JSON Response Using Groovy // set the example json response string (for a REST Request step assertion, use "def json = messageExchange.response.contentAsString") def json = '[{"firstName":"Bob","lastName":"Smith","uniqueId":146732,"thisIsAlwaysNull":null,"jobInfo":{"title":"","type":"Peon","code":42},"reviews":[{"date":"2017-06-01","type":"Regular","rating":"Adequate"},{"date":"2017-09-15","type":"Special","rating":"Other"}]},{"firstName":"Jack","lastName":"Jones","uniqueId":746381,"thisIsAlwaysNull":null,"jobInfo":{"title":"Big Boss","type":"Management","code":1},"reviews":[{"date":"2007-11-05","type":"Initial","rating":"Spectacular"}]},{"firstName":"Will","lastName":"Tell","uniqueId":574831,"thisIsAlwaysNull":null,"jobInfo":{"title":"Sweeper","type":"Peon","code":452},"reviews":[]}]' // parse json string using JsonSlurper - basically converts it to a groovy list def parsedJson = new groovy.json.JsonSlurper().parseText(json) // get data log.info " Count of people returned: " + parsedJson.size() log.info " Was Will's info returned (exists)? " + ( parsedJson.find { it.firstName == "Will" } != null ) log.info " Was Alice's info NOT returned (not exists)? " + ( parsedJson.find { it.firstName == "Alice" } == null ) log.info " First person's first name: " + parsedJson[0].firstName log.info " Index of person with ID 746381: " + parsedJson.findIndexOf { it.uniqueId == 746381 } log.info " Info for person with last name Tell: " + parsedJson.find { it.lastName == 'Tell' } log.info " Jack's ID: " + ( parsedJson.find { it.firstName == 'Jack' } ).uniqueId log.info " Jack Jones's job title: " + ( parsedJson.find { it.firstName == 'Jack' && it.lastName == 'Jones' } ).jobInfo.title log.info " All peon job type people's first names: " + ( parsedJson.findAll { it.jobInfo.type == 'Peon' } ).firstName log.info " Is Will's thisIsAlwaysNull null? " + ( ( parsedJson.find { it.firstName == 'Will' } ).thisIsAlwaysNull == null ) log.info " Will Tell's had this many reviews: " + ( parsedJson.find { it.firstName == 'Will' && it.lastName == 'Tell' } ).reviews.size() log.info " Bob's 2017-06-01 review rating: " + ( ( parsedJson.find { it.firstName == 'Bob' } ).reviews.find { it.date == '2017-06-01' } ).rating1.5KViews4likes0CommentsGmail OAuth 2.0 API Automation Example and example SubmitListener.beforeSubmit
Hi. Recently I had a use case where I had to verify that our application sends an email in a particular case. In my case, it was an email whenever a certain status is reached, but it could also be for instance the sending of an invitation (user-creation) email or whatnot. In essence: I want to check at a give moment when the status condition is reached that the email is delivered to the proper email address. In the past, there we some free email generators (like mailinator, 10minutemail,...) where you could get API calls to check the inbox, but I couldn't find any that offered that feature for free. So I decided to setup a dedicated gmail email address for my tests and talk to the gmail api to read the inbox (all messages), verify the subject and the actual content of a mail and delete the messages. More info on the gmail api here: https://developers.google.com/gmail/api/reference/rest. To get started, I created a gmail user and setup an OAuth2.0 google client Id (https://console.cloud.google.com/apis/credentials). These settings (clientId and secret) I used to setup an Authorization code grant as described here:https://support.smartbear.com/readyapi/docs/requests/auth/types/oauth2/grants/auth-code.html So far so good, the readyAPI internal browers showed me the google popup and I could manually insert the authentication that was needed to generate successfully an access token from google. BUT: When I tried to automate the flow in this popup using the example code provided in the documentation (=https://support.smartbear.com/readyapi/docs/requests/auth/types/oauth2/automate/sample.html) it did not work for me. Therefore I wanted to share the changes I made to it in order to get it working. Also the event handler SubmitListener.beforeSubmit(described on the same page) needed some rework for me to work properly. As an extra, I also have a test case setup script that deletes all emails in the gmail inbox so I have a proper starting situation for my tests. Hope this can help any other testers that would need this! Automation Scripts tab of the Auth Manager I have encrypted project properties that store my gmail username (gmailUser) and password (gmailPass). Page 1: // This function asks for permission to use OAuth. The user must be logged in to use it. Logging in is performed in the script below. function consent() { if (document.getElementById('submit_approve_access')){ document.getElementById('submit_approve_access').click(); } } // This function fills user password in when the user name is already known. It uses the project-level "pass" property. function fillpwd() { document.getElementsByName('password')[0].value = '${#Project#gmailPass}'; document.getElementById('passwordNext').click(); window.setInterval(consent, 1000); } // This script checks what page is displayed and provides the appropriate data. It uses the project-level "user" and "pass" properties. if (document.getElementById('profileIdentifier')) { document.getElementById('profileIdentifier').click(); window.setTimeout(fillpwd, 1000) }else if (document.getElementById('identifierId') && document.getElementById('identifierNext')) { document.getElementById('identifierId').value = '${#Project#gmailUser}'; document.getElementById('identifierNext').click(); window.setTimeout(fillpwd, 1000); } else if (document.getElementByType('password')) { fillpwd(); } else if(document.getElementById('submit_approve_access')){ window.setInterval(consent, 100); } Page 2: function consent() { if (document.getElementById('submit_approve_access')){ document.getElementById('submit_approve_access').click(); } } window.setInterval(consent, 100); Event handler SubmitListener.beforeSubmit: Note: There might be some redundant iteration of code in there, feel free to rewrite, main thing is: it works. I also expected that I could use the "Target" column to filter on the requests steps that start with "gmail*" but that didn't do it. So I fixed that in another way, together with providing some smart checking whether a new token generation is needed or not (gmail token is valid for 60 minutes). // Import the required classes import com.eviware.soapui.impl.rest.actions.oauth.OltuOAuth2ClientFacade; import com.eviware.soapui.support.editor.inspectors.auth.TokenType; import com.eviware.soapui.model.support.ModelSupport; import java.time.LocalDateTime import java.time.format.DateTimeFormatter def testStepName = context.getModelItem().getName() def expiresOn = context.expand('${#Project#expiresOn}') if (testStepName.toLowerCase().contains("gmail")) { // IF expiresOn == "" OR dateNow is > expiresOn then we need to get a new token. Otherwise the old should still do.... TimeZone.setDefault(TimeZone.getTimeZone('UTC')) TimeZone tz = TimeZone.getTimeZone("UTC") LocalDateTime dateNow = LocalDateTime.now() def patternUTC = "yyyy-MM-dd\'T\'HH:mm:ss.SSS\'Z\'" DateTimeFormatter dateFormatUTC = DateTimeFormatter.ofPattern(patternUTC).withLocale(Locale.US) String nowUtcFormat = dateNow.format(dateFormatUTC) LocalDateTime dateExpiresOn = dateNow.plusMinutes(55) String expiresOnUtcFormat = dateExpiresOn.format(dateFormatUTC) if (expiresOn == "") { /* log.info("Expires on is empty, so we need to run submitListener and get new token. We also write the new expiresOn to the project properties!") log.info("nowUtcFormat = " + nowUtcFormat) log.info("dateExpiresOn = " + expiresOnUtcFormat) log.info "let's run the submitListener.beforeSubmit to get a new accessToken. We know this one will be valid for 60 minutes, so we set a the expiresOn project property to now + 55 minutes" */ // Set up variables def project = ModelSupport.getModelItemProject(context.getModelItem()) project.setPropertyValue("expiresOn", expiresOnUtcFormat) def authProfile = project.getAuthRepository().getEntry("google") def oldToken = authProfile.getAccessToken() def tokenType = TokenType.ACCESS // Create a facade object def oAuthFacade = new OltuOAuth2ClientFacade(tokenType) // Request an access token in headless mode oAuthFacade.requestAccessToken(authProfile, true, true) // Wait until the access token gets updated int iteration = 0 while (oldToken == authProfile.getAccessToken() && iteration < 10) { sleep(500) iteration++ } // Post the info to the log log.info("Gmail authentication event handler: Project property \"expiresOn\" is empty! We get/set new token: " + authProfile.getAccessToken() + " with new expiresOn = " + expiresOnUtcFormat + ". The old token (with unknown expiresOn) was = " + oldToken) } else { def potentialNewExpiresOn = expiresOnUtcFormat //expiresOn retrieved from project properties dateExpiresOn = LocalDateTime.parse(expiresOn, dateFormatUTC) expiresOnUtcFormat = dateExpiresOn.format(dateFormatUTC) //log.info("dateExpiresOn = " + expiresOnUtcFormat) if (dateNow > dateExpiresOn) { // log.info "Expired! Let's get a new token..." // Set up variables def project = ModelSupport.getModelItemProject(context.getModelItem()) def authProfile = project.getAuthRepository().getEntry("google") def oldToken = authProfile.getAccessToken() def tokenType = TokenType.ACCESS // Create a facade object def oAuthFacade = new OltuOAuth2ClientFacade(tokenType) // Request an access token in headless mode oAuthFacade.requestAccessToken(authProfile, true, true) // Wait until the access token gets updated int iteration = 0 while (oldToken == authProfile.getAccessToken() && iteration < 10) { sleep(500) iteration++ } // Post the info to the log project.setPropertyValue("expiresOn", potentialNewExpiresOn) log.info("Token was expired! We get/set new token: " + authProfile.getAccessToken() + " with new expiresOn = " + potentialNewExpiresOn + ". The old token (expiresOn = $expiresOn vs now " + nowUtcFormat + ") was = " + oldToken) } else { //log.info "Not yet expired. Let's keep using the same old token (expiresOn = $expiresOn vs now " + nowUtcFormat + ")" } } } Setup script to delete all emails in the gmail inbox for proper start situation: I have a disabled test suite "WorkItem" with a test case named "GmailStartSituationCleanup" This test case has 4 steps: 1°GET gmail messagesList 2° Script "IterateOverAllGmailMessageIds" 3°DELETE gmail messageId 4°GET gmail messagesList-EmptyListCheck def testSuiteWorkItem = testRunner.testCase.testSuite.project.getTestSuiteByName("WorkItem") def testCaseGmailStartSituationCleanup = testSuiteWorkItem.getTestCaseByName("GmailStartSituationCleanup") testCaseGmailStartSituationCleanup.run(new com.eviware.soapui.support.types.StringToObjectMap(), false) The groovy test step 2°IterateOverAllGmailMessageIds = import com.eviware.soapui.support.JsonUtil def testStepAllMessages = testRunner.testCase.getTestStepAt(context.getCurrentStepIndex()-1) def teststepNameAllMessages = testStepAllMessages.getName() def testStepDeleteMessage = testRunner.testCase.getTestStepAt(context.getCurrentStepIndex()+1) testStepDeleteMessage.setDisabled(true) def testStepVerifAllDeleted = testRunner.testCase.getTestStepAt(context.getCurrentStepIndex()+2) testStepVerifAllDeleted.setDisabled(false) def responseStatus = testStepAllMessages.testRequest.response.responseHeaders["#status#"][0] if (responseStatus.contains("HTTP/1.1 2")){ def responseMessages = context.expand( '${'+teststepNameAllMessages+'#Response#$[\'messages\']}' ) if (responseMessages!= "" && responseMessages!= null){ def numberOfMessages = (JsonUtil.parseTrimmedText(responseMessages)).size() def id for (i=0;i<numberOfMessages;i++){ id = context.expand( '${'+teststepNameAllMessages+'#Response#$[\'messages\']['+i+'][\'id\']}' ) testStepDeleteMessage.setPropertyValue("messageId", id) log.info "Cleanup of gmail messages : Message "+(i+1).toString()+"/"+numberOfMessages.toString()+" with messageId $id will be deleted so we can continue with a proper starting situation..." testStepDeleteMessage.run(testRunner, context) } }else{ log.info "Cleanup of gmail messages : No messages found. We can continue with proper starting situation" testStepVerifAllDeleted.setDisabled(true) } }807Views3likes0CommentsHow to modify xml files using ReadyAPI
Modifying xml filesor simply working with xml strings might look difficult for a beginner so for those who need itI will try to break the whole thing into pieces so that it is easier to understand. Referring to nodes and attributes Let's say this piece of xml is stored in the file 'mijnFruits.xml' somewhere on your computer: <fruits> <apples> <apple color="red"/> <apple color="green"/> </apples> <oranges> <clementine> <mandarine> </oranges> <bananas/> <jabu-ticaba/> </fruits> If you would want to use a groovy script to identify a certain element, you'll first have to define a variable in which to parse the content: def xml = new XmlSlurper().parse("D:\\someFolder\\mijnFruits.xml") In order to refer to the 'clementine' node for instance, you would use: xml.oranges.clementine // For instance, the following will replace the node 'clementine' with 'tangerine' // xml.oranges.clementine.replaceNode { // tangerine '' // } Please note that while refering to any node, the root node (i.e. "fruits") is replaced by the variable in which the file is parsed (in our case 'xml'). That is why in our example we used 'xml.oranges.clementine' and not 'fruits.oranges.clementine' In order to refer to a node that has a certain attribute ( for instance <apple color="red"/> ), the syntax is as follows: // This will return a list will all the nodes 'xml.apples.apple' that have an attribute 'color' and the value 'red' xml.apples.apple.findAll{it.@color == "red"} // Hence, it is possible to check if such a node exists. For instance: //if (xml.apples.apple.findAll{it.@color == "red"}.size() == 0) // log.info("Such a node doesn't exist.") //else // log.info("Such a node exists.") If you want to refer to a node whose name contains dashes (example: 'jabu-ticaba') then the name must be placed inside single quotes like xml.'jabu-ticaba' // Example of node removing // xml.'jabu-ticaba'.replaceNode { } Practical examples Change an attribute value of a property import groovy.xml.XmlUtil import groovy.util.Node // Parse the content of the document and store it in the 'xml' variable def xml = new XmlSlurper().parse("D:\\someFolder\\web.config") // Change the attribute value for 'xxs-protection' xml.webApplication.'xss-protection'.@enabled = "false" // Construct a FileWriter object and assigns it to the variable 'writer' def writer = new FileWriter("D:\\someFolder\\web.config") // Write the changes to the file XmlUtil.serialize(xml, writer) // Close file writer.close() Add a new node import groovy.xml.XmlUtil import groovy.util.Node // Parse the content of the document and store it in the 'xml' variable def xml = new XmlSlurper().parse("D:\\someFolder\\web.config") // Add a node called 'conf' inside the <confs></confs> tags. The node will have 3 attributes (name, project and version) along with their corresponding values ('myName', 'myProj' and 'v0.0') xml.shortcutSection.shortcuts.appendNode { shortcut(name: "myName", project: "myProject", version: "v0.0") } // Construct a FileWriter object and assigns it to the variable 'writer' def writer = new FileWriter("D:\\someFolder\\web.config") // Write the changes to the file XmlUtil.serialize(xml, writer) // Close file writer.close() // The output will look like // <confs> // <conf name="myName" project="myProject" version="v0.0"/> // </confs> Add a more complex node import groovy.xml.XmlUtil import groovy.util.Node // Parse the content of the document and store it in the 'xml' variable def xml = new XmlSlurper().parse("D:\\mijn\\Web.config") // Add a more complex node (which contain more nodes or attributes) xml.'hibernate-configuration'.'session-factories'.appendNode { 'session-factory'(name: "test") { properties { property(name: "one hell of a property", value: "great of course") property(name: "another hell of a property", value: "great again of course") property(name: "avcsacsadsadsa", value: "asdsadsadasda") property(name: "asdsadsadas", value: "asdsadsadsa") property(name: "another hell of a property", value: "great again of course") } } } // Construct a FileWriter object and assigns it to the variable 'writer' def writer = new FileWriter("D:\\mijn\\Web.config") // Write the changes to the file XmlUtil.serialize(xml, writer) // Close file writer.close() Remove a node import groovy.xml.XmlUtil import groovy.util.Node // Parse the content of the document and store it in the 'xml' variable def xml = new XmlSlurper().parse("D:\\mijn\\Web.config") // Remove a node xml.shortcutSection.replaceNode { } // this removes the shortcutSection node along with its containments // Construct a FileWriter object and assigns it to the variable 'writer' def writer = new FileWriter("D:\\mijn\\Web.config") // Write the changes to the file XmlUtil.serialize(xml, writer) // Close file writer.close() Remove a node that contains a certain attribute import groovy.xml.XmlUtil import groovy.util.Node // Parse the content of the document and store it in the 'xml' variable def xml = new XmlSlurper().parse("D:\\mijn\\Groovy projects\\Web.config") // Delete a node that has a certain given attribute xml.'hibernate-configuration'.'session-factories'.'session-factory'.findAll{it.@name == "myName"}.replaceNode { } // Construct a FileWriter object and assigns it to the variable 'writer' def writer = new FileWriter("D:\\mijn\\Groovy projects\\Web.config") // Write the changes to the file XmlUtil.serialize(xml, writer) // Close file writer.close() Replace a node import groovy.xml.XmlUtil import groovy.util.Node // Parse the content of the document and store it in the 'xml' variable def xml = new XmlSlurper().parse("D:\\mijn\\Groovy projects\\Web.config") xml.configSections.replaceNode { noMoreConfigSection '' } // Construct a FileWriter object and assigns it to the variable 'writer' def writer = new FileWriter("D:\\mijn\\Groovy projects\\Web.config") // Write the changes to the file XmlUtil.serialize(xml, writer) // Close file writer.close() // The result would be that the configSections node i.e. // <configSections> // <section ...> // <section ...> // </configSections> // would be replaced by <noMoreConfigSection/>651Views0likes0CommentsHow to capture teststep status as pass/fail using groovy to write it in txt file
Question How to capture teststep status as pass/fail using groovy to write it in txt file Answer This can be done very simply by using the following TearDown Script: // Define variables for holding test suites, test cases and test steps def testSuites def testCases def testSteps // Get all the test suites from the project testSuites = project.testSuiteList File file = new File("C:\\Users\\luciana\\Desktop\\test.txt") /** * Iterate through each test suite, test case and test step */ testSuites.each() { // Log test suite name file << "-----------------------------------\n" file << "Running test suite: " + it.getName() + "\n" file << "-----------------------------------\n" // Get a list with the contained test cases testCases = it.getTestCaseList() testCases.each() { // Log test case name file << "-----------------------------------\n" file << "Running test case: " + it.getName() + "\n" file << "-----------------------------------\n" // Get a list with the contained test steps testSteps = it.getTestStepList() testSteps.each() { file << it.getName() + " - " + it.getAssertionStatus() + "\n" } } }569Views1like0CommentsHow to generate a random Number, String, AlphaNumeric string
Question How to generate a random Number, String, AlphaNumeric string Answer This below function will generate random Number, String, alphaNumeric string as what you pass in parameters. Refer below code and help yourself in generating random numbers. def num = generateRndString(10, "numeric"); log.info num def str = generateRndString(10, "string"); log.info str def alphaNum = generateRndString(10, "alphanumeric"); log.info alphaNum testRunner.testCase.getTestStepByName("Properties").setPropertyValue("RndNum", num) testRunner.testCase.getTestStepByName("Properties").setPropertyValue("RndString", str) testRunner.testCase.getTestStepByName("Properties").setPropertyValue("RndAlpha", alphaNum) def generateRndString(int num, String type){ def randValue = ""; if( type.equalsIgnoreCase("numeric") ){ def alphaNumeric = ('0'..'9').join() randValue = RandomStringUtils.random(num, alphaNumeric) while (randValue.size()!=num) { randValue = RandomStringUtils.random(num, alphaNumeric) } } else if( type.equalsIgnoreCase("string") ){ def alphaNumeric = (('a'..'z')+('A'..'Z')).join() randValue = RandomStringUtils.random(num, alphaNumeric) while (randValue.size()!=num) { randValue = RandomStringUtils.random(num, alphaNumeric) } } else if( type.equalsIgnoreCase("alphanumeric") ){ def alphaNumeric = (('0'..'9')+('a'..'z')+('A'..'Z')).join() randValue = RandomStringUtils.random(num, alphaNumeric) while (randValue.size()!=num) { randValue = RandomStringUtils.random(num, alphaNumeric) } } return randValue }535Views0likes0CommentsConvert a flat JSON object to x-www-form-urlencoded
Question How to create a Groovy script, which transforms a non-nested JSON object to thex-www-form-urlencoded format before sending it in the request body. Example: converting this object: { "name": "John", "age": 30, "city": "New York" } should result in this string: name=John&age=30&city=New%20York Answer def jsonData = ''' { "name":"John", "age":30, "city":"New York" } ''' def slurper = new groovy.json.JsonSlurper().parseText(jsonData) def str = new StringBuilder() def iter = slurper.keySet().iterator() while(iter.hasNext()){ def key = iter.next().toString() def value = slurper.get(key).toString().trim().replaceAll(" ","20%") str.append("$key=$value&") } log.info str[0..str.size()-2]500Views1like0CommentsGroovy Automated DataSource Loopers
Symptoms You may need to create the loop steps through groovy manually.So without further ado this is how I script my groovy loopers NOTE: in this example I am connecting to an OracleDB to fuel my requests. Solution 1) Structure: The structure within my test case is quite simple:loopStarterto connect to the db/initialise the data - storing the current information into properties,responseto send these properties off to the API through a request,loopEnderto either propagate or exit the loop if the condition is met. 2) loopStarter Connection to/creation of your data source, be it a database, excel etc In this example I will be using the groovy.sqlclass (documentation) to connect to my db, and store the results into properties import groovy.sql.Sql sql = Sql.newInstance(<connection details>) def res = sql.rows(<sql query>) def loopProperties = testRunner.testCase.getTestStepByName("loopProperties") //will initialise count in the loopProperties step if count does not yet exist if(!loopProperties.hasProperty("count")){ loopProperties.setPropertyValue("count","0") } def count = Integer.parseInt(loopProperties.getPropertyValue("count")) //store the properties from the current result loopProperties.setPropertyValue("x",res[count].x) loopProperties.setPropertyValue("y",res[count].y) loopProperties.setPropertyValue("querySize",(String)res.size()) sql.close() sql.rows returns an array of ArrayLists, so to access the current result (more on this later) we will use res[count]. Just to reiterate this step ONLY sets the properties to be sent off in the request.querySize is set so we can continue looping over all the results from the query. 3) response To then call your properties into your request step we will do this: <soapenv:Envelope namespace:ns="namespace"> <soapenv:Header/> <soapenv:Body> <ns:x>${loopProperties#x}</ns:x> <ns:y>${loopProperties#y}</ns:y> </soapenv:Body> </soapenv:Envelope> if you choose not to store your properties in a property step and wanted to store them at the test case level you can fetch them like so: ... <ns:x>${#TestCase#x}</ns:x> ... 4) loopEnder This is the loop exit condition. It will tell the loop whether or not there are more results from your query to send through the request. This is also a pretty simple step: - check count vs querySize - increment count if true - go to loopStarter if true, to update the properties (count has been increased andbecause of this, so will the current result) def loopProperties = testRunner.testCase.getTestStepByName("loopProperties") def count = Integer.parseInt(loopProperties.getPropertyValue("count")) def querySize = Integer.parseInt(loopProperties.getPropertyValue("querySize")) if( count<querySize-1 ){ count = count+1 loopProperties.setPropertyValue("count", (String)count) testRunner.gotoStepByName("loopStarter") } 5) reset count Unnecessary step but I like getting into the habbit of clearing all properties after I'm done, and this groovy script will do it for you def loopProperties = testRunner.testCase.getTestStepByName("loopProperties") String[] removals = loopProperties.getPropertyNames() for(i=0;i<removals.size();i++){ loopProperties.removeProperty(removals[i]) } I've been thinking of doing something similar to this for the Excel DataSource scriptOlga_Tmentioned, well similar to the loopStarter step anyway - doing it completely through groovy so SoapUI free users can do it too, I just need to look into parsing exel files with groovy. Anyways I hope this helps you all, Mo490Views0likes0CommentsCode for groovy datasource
Question generates some identification codes like X00001, X00002 and so on... Answer // Get current row def row = testRunner.testCase.testSteps["DataSource"].currentRow // Declare an array that will contain the id codes def codes = [] // Generate all id codes for (int i = 1; i < 100000; i++) { codes.add( String.format('X%05d', i) ) } // Make the values reachable from the datasource if (row < codes.size()) { // Return the name to data source's "File" property result["Code"] = codes[row] }467Views0likes0CommentsAutomated testing with Jenkins and bypassing Tests
I recently started working with my DevOps team to automate our ReadyAPI projects in Jenkins so we can automate some parts of our tests instead of having to manually re-check defects as they are fixed. The intent is to eventually end up automating a lot more but this was a great start. The problem I ran into was that, with the way our projects are stored in GitLab, there are some tests that may fail (rightfully so) depending on which environment was last tested against and where the automated test is running. My original plan was to use Tags to control what tests to run in Jenkins, but you can only specify which tags to run and not which ones to exclude. I did a bit more research and came up with a solution. I can likely improve on it with events now that I have started researching that, but I wanted to share. I set a Project level property called "Automated" and set it to false. This can be overridden with the testrunner.bat/testrunner.sh with a command line argument of "-PAutomated=true", so that the value is only ever true when it runs on Jenkins and the appropriate argument. With that, I put a groovy script test step at the beginning of the tests that would parse the value of Automated, and disable certain tests if the value was true, and re-enable them if the value was false. Example script here: def automated = context.expand( '${#Project#Automated}' ).toBoolean(); if (automated == false) { context.testCase.testSuite.testCases["TestCase1 to D isable"].setDisabled(false); context.testCase.testSuite.testCases["TestCase2 to D isable"].setDisabled(false); } else { context.testCase.testSuite.testCases["TestCase1 to Enable"].setDisabled(true); context.testCase.testSuite.testCases["TestCase2 to Enable"].setDisabled(true); }461Views0likes0Comments