Forum Discussion

bqualters's avatar
bqualters
Occasional Contributor
3 years ago
Solved

New to SoapUi and programming...can anyone tell me what "No signature of method..blah blah" means?

As a new SoapUI user I am TRYING to learn how to write basic code ...and often get error messages that start with "No signature of method blah blah blah" - like for example the split command.  The me...
  • ChrisAdams's avatar
    3 years ago

    Hi,

     

    Before we look at your questions, my examples are all based on a simple 'CUST' table.  This table has five columns:-

    • ID
    • SURNAME
    • FORENAME
    • STREET
    • CITY

    In my table, I have this dataset...

    ID SURNAME FORENAME STREET CITY
    1 Jones Steve Market St London
    2 Brown James New St Salford
    3 Head Michael Newby St Liverpool
    4 Marr Johnny Bridge St Manchester

     

    Firstly, split method.  The split method is used to split a string into an array using some character.

    The below example shows how you can use split, but its a faff.

            log.info("Get all customers")
            def custSql = "select * from cust where id = 1";
            def customers = dbConn.rows(custSql);
            // Let's have a look at db response.
            log.info(customers);
    
            // The response is split by commas, but the below will not work.  This returns the error you asked about.
            // customers is an array list and there is no split method for that object type.
            // String[] mySplitArray = customers.split(",");
            
            // However, the string object does have a split method.  Let's convert our array list to a string.
            def myArray = customers.toString();
            log.info(myArray);
            String[] mySplitArray = myArray.split(",");
            log.info(mySplitArray);  //Just returns an object id.  We now need to work with this as an array.
    
            for (row in mySplitArray){
                log.info(row);
            }

     

    How to find column names.  I'm using Oracle and there is a query find the columns in a table.  See the below example..

            log.info("Getting column names");
            def columnSql = "select column_name from user_tab_cols where table_name = 'CUST'";
            def columns = dbConn.rows(columnSql);
    
            // Columns is an array list, so the following log statement will return column names as an array list
            log.info(columns);
    
            // Because columns is an array list, we can find the number of columns using the size() method.
            // The ${something} syntax interpolates the variable into the string to display.
            // Much neater than joining values together like.... log.info("Number of columns is " + columns.size() + ".");
            log.info("Number of columns is ${columns.size()}.");
    
            // We can iterate over the array list by using for each.  E.g.
            for(column in columns){
                log.info(column); // Returns something like a key/value pair.
                log.info(column["COLUMN_NAME"]); // Returns just the actual name.
            
            }
    
            // Becuase we know the number columns, we can also use a traditional for loop.
            for (int i = 0; i < columns.size(); i++) {
                def columnName = columns[i]["COLUMN_NAME"];
                log.info("The column name at postion ${i} is ${columnName}.");
            }

     

    With the ability to find column names, we can use this with a query to tease out values from a record.  See below....

            // Without knowing the column names, we can still query the CUST table and log each column value.
    
            log.info("Getting column names");
            def columnSql = "select column_name from user_tab_cols where table_name = 'CUST'";
            def columns = dbConn.rows(columnSql);
    
            def custByIdSql = "select * from cust where id = 1";
            def cust = dbConn.rows(custByIdSql);
    
            for(column in columns){
                def currentColumn = column["COLUMN_NAME"];
                log.info(cust[0][currentColumn]);
            
            }

     

    We can apply this to a query that returns multiple rows....

            // Without knowing the column names, we can still query the CUST table and log each column value.
    
            log.info("Getting column names");
            def columnSql = "select column_name from user_tab_cols where table_name = 'CUST'";
            def columns = dbConn.rows(columnSql);
    
            log.info("Get all customers")
            def custSql = "select * from cust";
            def customers = dbConn.rows(custSql);
    
            // Iterate over each customer record, and for each customer, iterate over the column names and put the details into a single line.
            for(customer in customers){
                def customerString = "";
                for(column in columns){
                    def currentColumn = column["COLUMN_NAME"];
                    customerString += currentColumn + " - " + customer[currentColumn] + ".  ";
                }
                log.info(customerString);
            }

     

    So, this is all great if the query selects all columns.  E.g. select * from cust.  But in your question, you say you don't know what columns may have been asked, so need to find a way to tease out the column names from the response.

     

    Here's an example....

            // Your example db response looks like [SKU:TRANS SKU SNIND E, DESCRIPTION:Trans SKU w/ SNI E]
            // It's likely in an array list, so turn it into a string.  I've called the db rows response dbResponse for the example.
            // def myString = dbResponse.toString()
            
            // Here I have to assume myString looks like [SKU:TRANS SKU SNIND E, DESCRIPTION:Trans SKU w/ SNI E]
            def myString = "[SKU:TRANS SKU SNIND E, DESCRIPTION:Trans SKU w/ SNI E]";
    
            // Now we can split...
            def myArray = myString.split(",");
    
            log.info(myArray[0]);
            log.info(myArray[1]);
    
            // In your Q, you wanted variable names that includes the row number.  That's tricky and not something I'd recommend.  For a kick off, 
            // I wouldn't know how to create a dynamic variable name, and if they're dynamic how will you reference them later?  Personally, I'd stick with arrays...
    
            def columns = [];
    
            for (item in myArray) {
                // Some entries have a [ or a ].  Lets get rid.
    
                item = item.replace("[", "");
                item = item.replace("]", "");
    
                // Each 'item' is a name value pair sepated by a colon.  We can use that to split again.
                def nameValue = item.split(":");
    
                // The column name is always the left-hand side of the pair, so we only need element zero.
                def columnName = nameValue[0];
                columns.add(columnName);
    
                // We could have done 
                // columns.add(nameValue[0])
    
            }
            // Nice, we now have the columns from db response.
            log.info(columns.toString());
    
            // With this column array, you can now pull values from your db response by applying some of the earlier examples above.

     

     

  • ChrisAdams's avatar
    3 years ago

    Hi,

    Typically, I head straight to Google.  The intellisense in ReadyAPI isn't great and I don't rely on it.  

     

    If I want to know what methods are available, I search for the class definition using Google.  When looking at your issue and found db responses were an array list, I Googled that.  So a couple of points there, if you have some variable and you want to know the class, use the getClass() method.  E.g.

     

     

    // This will log the class name for a given object.
    log.info(myObject.getClass());
    
    // This returns class.java.util.ArrayList

     

     

    Googling the class name took me to the official Java docs and this page... ArrayList.html 

    From here I could then see the methods available to me.

     

    java.utils are already imported, so no issues there in calling methods.  But, I'd take the same approach to find the lib to import.

     

    For example, here is some Groovy script to load a file.

     

    def fullFilePath = "c:\temp\some-file-of-interest.txt";
    
    log.info("Opening file ${fullFilePath}.");
    
    String fileContents = new File(fullFilePath).text;
    
    return fileContents;

     

     

    This will throw an error because of a missing import.  Here, I would Google something like, "groovy java new File example".  The first link in the results took me to tutorialspoint.com.

     

    And there is the import....

    In this case, that's job done.

     

    I know you said not to focus on Split, but it's worth a quick look.  In your original post, you mentioned


    So I tried to use a split command like this:     currRec = split( "$row."+recordNum,",")  (where recordNum was the row indicator number to get the above data) BUT it errors telling me -->

    groovy.lang.MissingMethodException: No signature of method: Script51.split() is applicable for argument types: (String, String) values: [[SKU:TRANS SKU SNIND E, DESCRIPTION:Trans SKU w/ SNI E].1, , ] Possible solutions: split(groovy.lang.Closure), wait(), sprintf(java.lang.String, [Ljava.lang.Object;), sprintf(java.lang.String, java.lang.Object), inspect(), wait(long) error at line: 26

     

    SO WHAT AM I EXPECTED TO DO HERE????  Is 'split' really not a valid method???

    Do I need to import a library?  If so, how do you figure out which library needs to be imported?  

     


    This isn't a missing import.  split("something",",") won't work.  Here, whatever example you've borrowed from, is saying there is a function called split that takes two parameters.  There isn't and that's what this part of the error "split() is applicable for argument types: (String, String)" says.

     

    How to approach this?  Back to Google and search for "java groovy split".  Again, first hit is tutorialspoint and an example...

     

    Split isn't a function.  It's a method on the string class, we need to call it like "hello-world".split("-") instead of split("hello-world", ",")

     

    Thinking about imports in general, I can only actually think of a handful I've had to use.  These are for file handling, SQL and database connectivity, JSON parser and XML Parser.  Everything else I've done is using core language without imports.  If something went wrong with my scripts, I'd definitely be more inclined to think I have a code error before an import issue.

     

    There are some great and some not-so-great resources out there.  For things Groovy and SoapUI?ReadyAPI related, have a look at ou-ryperd.net .  This is an excellent resource and one I have recommended three times in the last fortnight.  There is also StackOverflow, which can be a mixed bag.

     

    But, this forum is the best for Groovy with ReadyAPI or SoapUI.  Don't struggle, fire off lots of questions, even if you think too simple or too obvious.  Typically, quick/easy problems are answered very, very fast.  I know you had to wait a few days for a response to this thread, but there were a few things to think about!

     

     

     

  • bqualters's avatar
    bqualters
    3 years ago

    And THAT folks...is how you answer a question!  Thanks Chris - tons of info here.  My problem is I am a self taught WinRunner /UFT tester who has zero classroom training on scripting of any sort, so I carried alot of expectations over to Groovy that I shouldn't - like a good built in reference manual.  But hey..that's why it's free...the error messages are NOT very intuitive - as you pointed out with the split example..I thought since it showed the (string,string) that it recognized the syntax but that I needed to load a library to be able to use it...again - BOOKMARKING this answer as a reference for future stuff.  I am making pretty good progress on creating an engine to automatically run my functional testing stuff - knowing the basics of the language will make it alot easier so THANK YOU!