To whet pre-jump appetites, the SoapUI primary structure:
- Project - houses...
- Methods - Create these including parameters that need populating later (I'm doing REST atm)
- TestSuite - One can only script within a test suite/case so we'll need one
- TestCases - one for each separable chunks of work.
Lots of choices but I've mostly used... - GroovyScript - code to generate values (like hashes)
- PropertyTranfer - Used to copy values between scripts and calls' parameters (REST calls, etc)
- Test Request (REST/SOAP/HTTP/JDBC/AMF!) to make actual calls
- Setup Script and TearDown Script can be placed on TestSuite, TestCase, etc to also house the scripting. (but I've generally found scripts more handy.)
- Project-wide utility methods can only be defined with a SoapUI Pro license (IIUC). Without this, I've ended-up with some copy-and-paste re-use :-( Shame there's no sliding scale from Community to Pro!
So, the rest of this post is in the context of my RTM Android Sharer but I hope it'll be sufficiently general to be helpful. Why was I using SoapUI when I'm coding Android? Well, I wanted to confirm my understanding of the RememberTheMilk API -- specifically, to test:
- connectivity
- authentication
- creating a task with...
- a URL
- a note
- a set of tags
- retrieving a list of tags to auto-suggest for the list above (later)
- Create the basic SoapUI REST structure + methods
(may add more detail if people interested / I fear I'll forget) - Create a test suite
- Create TestCases for separable chunks of work.
(logging in, creating a task, etc) - Add Properties to Suite/TestCase/... to act as global variables to move data through (bletch!)
(e.g. auth_token needs passing to all calls once received from previous call so stash now and retrieve as described in PropertyTransfer section below) - Add GroovyScript items to do some operations -- in my case the api_sig generation.
- Add REST Test Requests with both populated and empty parameters
- Add PropertyTranfer to move data between steps (see below)
- To ensure everything's going well, throw in some assertions on the results.
(such as XPath /rsp/@stat to confirm the root "rsp" element has a "stat" attribute whose value "ok" one places in the "Expected Result" field.)
Wow, are these powerful!
As mentioned above, I found it handy to create holder-slots on the Test Step (/ Case / Suite depending how widely something was useful) and transferring values from a previous Response to these for future use. Not sure whether that's best practise but it definitely works :-)
Data transfer slightly different depending upon source...
- XML Response results:
- XQuery is optional, XPath is used if not selected and that's plenty powerful!
- Retrieve text values with /rsp/timeline
(will retrieve from <rsp><timeline>DATA</...></...>) - Retrieve attribute values with /rsp/@stat
(will retrieve from <rsp stat="DATA"></...>) - Some simple mouse/eyeball errors ...
- Error:
net.sf.saxon.trans.XPathException: XPath syntax error at char 9 in {/rsp/list@id}: Unexpected token "@" beyond end of expression
Cause: Missing "/" before "@". Should be /rsp/list/@id - Error:
Missing match for Source XQuery [/rsp/list/@id]
Cause: Erroneously ticked XQuery -- you're using XPath but selected to use XQuery. Make up your mind ;-) - Error:
java.lang.reflect.InvocationTargetException
Cause: Likely both (1) and (2) = Missing "/" and erroneously ticked XQuery. - Script results:
- return from your Groovy script and select script result to pull out. It's how I did the MD5 hashing above.
- To transfer data into a script, stash the value in a property and retrieve. Rather than using navigation via testSuite or testCase, it's usually easier to use the context's expander since it's uniformly available in all scripts (so doesn't require copy-and-paste editing if you lack SoapUI Pro for global libraries). E.g:
- To retrieve a custom property "api_key" from the TestSuite,
- Rather than ...
def api_key = testSuite.properties."api_key".value; (which will only work when you have testSuite available which might require navigating to it from other variables)
- ... use ...
def api_key = context.expand('${#TestSuite#api_key}');
Great tips to have a look at:
- The docs are a little discontinuous so here're my favourite janky links:
- soapUI Tips & Tricks (fantastic jumpstart on all scripting!)
- SoapUI object model
- Note XmlHolder may not seem to be giving a powerful enough return type (e.g. String!). Instead of using its getNodeValue(xpath) to get Xml Node then doing details, usually better to make a smarter XPath query that returns exactly what you wanted to test. E.g.
- To find the value attribute of the api input field in the loginform,
- Once one has the XmlHolder by..
import com.eviware.soapui.support.XmlHolder; log.info "messageExchange: "+ messageExchange; def holder = new XmlHolder(messageExchange.responseContentAsXml); assert null != holder;
- ... rather than...
def apiNodeValueAttr = holder.getDomNode("//form[@id='loginform']/input[@name='api']/@value"); assert null != apiNodeValueAttr; log.info "apiNodeValueAttr: "+ apiNodeValueAttr; def value = apiNodeValueAttr.getNodeValue(); assert null != value; log.info "api node value: "+ value;
- ... use...
def apiNodeValue = holder["//form[@id='loginform']/input[@name='api']/@value"]; assert null != apiNodeValue; log.info "apiNodeValue: "+ apiNodeValue;
- XPath wildcards don't work in 3.6.1 but allegedly fixed in 3.6.2. Tried but doesn't seem to be as of 2011/04/23.
- Unverified: Disabling Assertions doesn't seem to be saved?
- ...(maybe done / maybe more to follow as I discover)...
p.s. Can sanitize and post the project if it'd be handy. (no, you're not having my RTM API key :-P )
No comments:
Post a Comment