10. Request and Response Handling Using Scripts

Request and response handling using Scripts:

soapUI provides us with a few important APIs to use with request and response messages:

1. com.eviware.soapui.support.GroovyUtils: The API documentation of the GroovyUtilsclass (http://www.soapui.org/apidocs/com/eviware/soapui/support/GroovyUtils.html) provides us with all the necessary information to use this API.

2. com.eviware.soapui.support.XmlHolder: This is a very useful API to act upon XML request and response messages. More details about the API can be found at the official API documentation (http://www.soapui.org/apidocs/com/eviware/soapui/support/XmlHolder.html)

3. com.eviware.soapui.model.iface.MessageExchange: This interface represents an exchange of request and response messages using various API methods. For more details, visit http://www.soapui.org/apidocs/com/eviware/soapui/model/iface/MessageExchange.html.

Let's find out the basic usage of each of these classes using our sample project.

1. Add a new Groovy Script TestStep under the getRoomDetails TestCase of RoomManagementService TestSuite.

2. Add the following script:

def xmlHolder = new com.eviware.soapui.support.XmlHolder(context, "getRoomDetails#Response")
log.info xmlHolder.getXml()

Here, we created a new XmlHolder object which makes use of WsdlTestStep context variable and response of getRoomDetails request through property expansion. Submit the getRoomDetails TestStep once so that we will have a valid response in context. Then, run the Groovy script which will execute the script against the last received response message. You will find the response SOAP message in the script log.

3. We can get hold of the response XML message using the GroovyUtils class as follows:

def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
def xmlHolder = groovyUtils.getXmlHolder("getRoomDetails#Response")
log.info xmlHolder.getXml()


4. Similarly, the request message can also be accessed:
 
def xmlHolder = new com.eviware.soapui.support.XmlHolder(context, "getRoomDetails#Request")

Once you get hold of request and response messages, you can do various XML manipulations through the methods included in the XmlHolder class such as getDomNode(xpath) and getNodeValue(xpath).

Script assertion:

Script assertion is another type of assertion that can be used to validate the responses. The major advantage of using script assertion over the other assertions is you have much more control over the messages exchanged. Thus, you can validate the message content or headers using Groovy or JavaScript.

1. Open the getRoomDetails test request editor. Click on the Assertions tab at the bottom pane and select the Adds an assertion to this item option. Select Script Assertion and click on OK:

Script assertion

3. At the upper-right of the script editor, you will notice the message, "Script is invoked with log, context and messageExchange variables". Thus, you can use these variables to access request and response messages to do various content level validations.

4. The com.eviware.soapui.model.iface.MessageExchange interface represents an exchange of request and response message in a test run. Therefore, we can use the methods exposed by this interface such as getResponseContent() and getResponseHeaders() to access the request and response messages.

5. Add the following script in the script assertion editor and run the getRoomDetails TestCase:

import com.eviware.soapui.support.XmlHolder
def responseHolder = new XmlHolder(messageExchange.getResponseContentAsXml())
def requestHolder = new XmlHolder(messageExchange.getRequestContentAsXml())
assert responseHolder["//ns:roomNumber"] == requestHolder["//typ:roomNumber"]

We used two XmlHolder objects to hold request and response. Request and response messages were retrieved by calling the getReponseContentAsXml and getRequestContentAsXml methods of the messageExchange object.

This is a trivial example which we used to demonstrate the usage of script assertion in a soapUI project. By using the context and messageExchange variables, you can try out much advanced and comprehensive operations on request and response messages.

9. SOAPUI Model Items

ModelItems are the preliminary building blocks of a soapUI project. The elements such as projects, test suites, test cases, test steps, mock services, mock responses, and assertions are all implemented as ModelItems.

The com.eviware.soapui.model.ModelItem interface (http://www.soapui.org/apidocs/com/eviware/soapui/model/ModelItem.html) is the super interface which defines the general behavior of all soapUI model items.

When you get hold of a Model Item in your script, you can use the corresponding getters to retrieve values such as id, name, and description of a ModelItem.

For Example:

getRoomDetailsTestCase.name

ModelItems provide us with various methods to access parent and child entities.
Let's look at some methods in TestCase ModelItem that are frequently used to retrieve TestSteps in a TestCase:

1. getTestStepByName(String stepName): To retrieve a specific test step inside a TestCase.

2. getTestStepCount(): To get the TestStep count of a TestCase

3. getTestStepList(): To get list of TestSteps included in a TestCase

Add the following script as a Groovy Script TestStep in any of the TestSuites in the HotelReservation sample project and run the TestStep:

import com.eviware.soapui.impl.wsdl.teststeps.*
def getGuestDetailsTestCase = testRunner.testCase.testSuite.project.testSuites["GuestManagementServiceTestSuite"].testCases["getGuestDetails TestCase","Delay"]
//To get specific test
stepgetGuestDetailssoapStep = getGuestDetailsTestCase.getTestStepByName("getGuestDetails")
log.info("Name of the TestStep: "+getGuestDetailssoapStep.getLabel())
//To get test step 
countlog.info("Number of TestSteps in getGuestDetails TestCase: "+getGuestDetailsTestCase.getTestStepCount())
//To get all test steps
for(teststep in getGuestDetailsTestCase.getTestStepList())
log.info("Name of the TestStep in getGuestDetails TestCase: "+teststep.getName())

Assuming that we have two TestSteps, getGuestDetails and Delay, in the getGuestDetails TestCase, the script log output will show results similar to the following:

INFO:Name of the TestStep: getGuestDetails
INFO:Number of TestSteps in getGuestDetails TestCase: 2
INFO:Name of the TestStep in getGuestDetails TestCase: getGuestDetails
INFO:Name of the TestStep in getGuestDetails TestCase: Delay

Once we get hold of the TestStep object as described above, we can try out many interesting things. Suppose we want to add an assertion to a specific step in a TestCase, we can obtain the required TestCase first, traverse through all the TestSteps of the TestCase and add the necessary assertion programmatically as shown in the following script:

import com.eviware.soapui.impl.wsdl.teststeps.*
def getGuestDetailsTestCase = testRunner.testCase.testSuite.project.testSuites["GuestManagementServiceTestSuite"].testCases["getGuestDetails TestCase"]
//Define the type of assertion
def soapAssertion ="SOAP Response"
//Retrieve all TestSteps in getGuestDetailsTestCase
for(testStep in getGuestDetailsTestCase.getTestStepList())
 { 
//Check whether the TestStep is a SOAP Request TestStep    if(testStep instanceof WsdlTestRequestStep)    
testStep.addAssertion(soapAssertion)
}

we accessed the child TestSteps of the getGuestDetails TestCase, the parent TestSuite can also be retrieved using getGuestDetailsTestCase.getTestSuite().

We looked into some preliminary methods of soapUI ModelItems which can be used to manipulate various elements and operations in a soapUI project. So far, we have worked with scripts which have been inside Groovy Script TestSteps. However, Groovy Script step is not the only place where you can write your script. There are more:

1. Setup and TearDown Scripts at TestCase, TestSuite level which can be used to initialize and clean up various resources used in a soapUI test
2. Load Script at project level which is used to run a script after loading the project
3. Script assertion to introduce arbitrary validation on response
4. MockService-specific scripts

Setup and TearDown scripts in soapUI

Setup and TearDown scripts can be used for many purposes. In particular, if you want to initialize something which is applicable for the whole TestSuite or TestCase, the Setup script will be the most appropriate option. Let's look at how we can initialize database connection in RoomManagementServiceTestSuite using Setup Script:

1. Right-click on RoomManagementServiceTestSuite and select Show TestSuiteEditor.
2. Select Setup Script at the bottom pane and add the following script:

import groovy.sql.Sql;
def DBdriver="com.mysql.jdbc.Driver"
def DBpath="jdbc:mysql://localhost:3306/HOTEL_RESERVATION_DB"def username='root'def password='root'
try {
     DBconnection = Sql.newInstance(DBpath, username, password, DBdriver);
context.setProperty("dbConProp", DBconnection)

catch (Exception e) {
log.error "Could not establish connection to the database."
}

Here, we used Groovy SQL library to establish a database connection to our sample HOTEL_RESERVATION_DB. Once the connection is established, in order to use the connection from anywhere in the TestSuite, we set the connection as a context property, dbConProp:

Setup and TearDown scripts in soapUI

3. Now, we can use this connection within the RoomManagementTestSuite. In order to demonstrate the usage of the connection, let's add a simple Groovy Script TestStep under the addRoom TestCase:

def statement = "insert into ROOM_T values(500, 'Luxury', 'Double')"
def DBCon = context.getProperty("dbConProp")
DBCon.execute(statement)

Here, we simply used the dbConProp context property to execute a SQL query. Run RoomManagementServiceTestSuite and query the ROOM_T table. You will find the query has been executed successfully.

Similarly, TearDown Scripts can be used to close database connections at the end of the TestSuite execution.

4. Click on the TearDown Script tab at the bottom pane of RoomManagementServiceTestSuite and add the following script to close the database connection:

def DBCon = context.getProperty("dbConProp")
DBCon.close()

Load Script at soapUI project level

If we need to do something common for the whole project, we can invoke a script at the project level. In the soapUI project view, you will find Load Script and Save Script tabs at the bottom pane, where you can specify a script at the project level and run it just after loading the project

In SOA testing, we usually need to use the same soapUI project in multiple environments. Before deploying the web services in the QA environment, developers may execute the whole set of test suites in the development environment. 

Similarly, the same tests will be executed in the staging environment before moving the services into production. Usually, in all these cases, nothing but the service endpoints are changed. Therefore, it will be necessary to change all endpoint URLs when moving the TestSuites among different environments. To address that, we can use a simple Groovy script at the project level and run it before deploying the test in different test environments.

Assume the following are the URLs of three of our sample web services when they are deployed in the QA environment:
  • http://QAServer:8080/axis2/services/GuestManagementService
  • http://QAServer:8080/axis2/services/RoomManagementService
  • http://QAServer:8080/axis2/services/ReservationService

Let's look at how we can change the existing endpoints of the SOAP request TestSteps in our sample project when moving the test into the QA environment.

1. Right-click on HotelReservationProject and select Show Project View. Then click on the Load Script tab on the bottom pane to open the script editor.

2. Add the following script:

//Define three web service endpoints 
def GuestQAEndpoint = "http://QAServer:8080/axis2/services/GuestManagementService"
def RoomQAEndpoint = "http://QAServer:8080/axis2/services/RoomManagementService"
def ReservationQAEndpoint = "http://QAServer:8080/axis2/services/ReservationService"
 //Get all TestSuites inside HotelReservationProject 
testSuiteList = project.getTestSuites() 
//Iterate through each TestSuite 
testSuiteList.each
{
 //Rerieve a particular TestSuite by its name 
testSuite = project.getTestSuiteByName(it.key) 
//Get all TestCases inside particular TestSuite 
testCaseList = testSuite.getTestCases()
//Iterate over each TestCase of a particular TestSuite testCaseList.each  

 //Retrieve specific TestCase by its name  
testCase = testSuite.getTestCaseByName(it.key)
//We do not want to set endponts for all TestSteps in a TestCase.
// So, get only the SOAP Request TestSteps  
soapTestStepsList = testCase.getTestStepsOfType(com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep.class)   
//Iterate over each SOAP Request TestStep in a TestCase  soapTestStepsList.each  
{  
 //Assign the relevant endpoint   
if(testSuite.name == "GuestManagementServiceTestSuite")
       {   
           it.properties['Endpoint'].value = GuestQAEndpoint   
        }
else if (testSuite.name == "RoomManagementServiceTestSuite")
      {   
        it.properties['Endpoint'].value = RoomQAEndpoint   
        }else {   
             it.properties['Endpoint'].value = ReservationQAEndpoint                      }  
      } 
      }
 }

We will not go through each line in the previous script as everything is explained as inline comments. Note that we used Groovy closure style looping and the keyword it (it.key) to get the specific TestCase and TestSuite names from the list objects.

3. Run the script by clicking on the green arrow icon at the upper-left corner of the Script window. Check the SOAP Request TestSteps of each TestSuite. You will notice that the default endpoints of all SOAP requests are changed accordingly.


8. The testRunner Variable

The testRunner Variable:

  • The testRunner variables are used to execute tests in a soapUI project.
For example:

The com.eviware.soapui.model.testsuite.TestCaseRunner interface, that extends com.eviware.soapui.model.testsuite.TestRunner, defines a set of methods to manipulate soapUI TestCases. 

Here we will look into the usage of testRunner inside a soapUI project.

The testRunner interfaces provide methods such as start, cancel, and fail to control the test execution. Follow these steps to see how testRunner can be used to control test execution flow:

1. Add the following statement in GroovyTestScript1 and run the getRoomDetails TestCase from the getRoomDetails TestCase editor:

testRunner.cancel("CANCELLED THE TEST")

2. We will see that the further executions of TestCase immediately stop when they reach the preceding statement and the CANCELLED THE TEST message is logged at the TestCase log. This is useful if you want to cancel the test run, based on evaluation of certain conditions.

Let's look at how we can invoke a different TestCase in a different TestSuite using testRunner.

Suppose in our sample HotelReservation project, the addReservation TestCase should fail if the corresponding room does not exist in the system (note that, in the ReservationService implementation, we have not added a validation to check the availability of rooms).

Thus, before invoking the addReservation TestCase, we may need to check the existence of the room which is going to be reserved. In this case, of course we can directly use the Run TestCase TestStep. However, let's try to use a GroovyScript TestStep as a child of addReservation TestCase to invoke getRoomDetails TestCase so that we can look in to the possibilities of using the testRunner object:

1. Select ReservationServiceTestSuite and add Groovy Script TestStep as an immediate child of addReservation TestCase. Name it findRoomScript.

2. Add the following script:

import com.eviware.soapui.model.testsuite.TestRunner.Status
//Get hold of the getRoomDetails TestCase which is at a different 
// TestSuite than the current Suite
def getRoomDetailsTestCase = testRunner.testCase.testSuite.project.testSuites["RoomManagementServiceTestSuite"].testCases["getRoomDetails TestCase"]
//Run the getRoomDetails TestCase synchronously
def testcaserunner = getRoomDetailsTestCase.run(null, false)
//Fail if getRoomDetails TestCase fail
assert testcaserunner.status == Status.FINISHED

Here, we first got a reference to getRoomDetails TestCase. Then, we invoked the run(stringToObjectMap properties, boolean async) method of the WsdlTestCase class (com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase) that implemented the TestCase interface (http://www.soapui.org/apidocs/com/eviware/soapui/impl/wsdl/testcase/WsdlTestCase.html). Finally, we used assert statement to check the status of the TestCase execution.

3. Give an existing room number as value in <typ:roomNumber> in getRoomDetails SOAP request. Also, specify the same room number in the addReservation SOAP request. Run ReservationTestSuite. Make sure to disable GroovyTestScript2 TestStep, which has been added previously to cancel the execution of getRoomDetails TestCase:

The testRunner variable

The TestCase log will be updated with the results, where you can find the findRoomScript is marked in green, denoting the success of execution of the getRoomDetails TestCase.

4. Now, submit the getRoomDetails TestStep of RoomManagementService TestSuite with a non-existing room number. We should add an assertion to denote that the getRoomDetails TestStep of the getRoomDetails TestCase fails if we submit the getRoomDetails SOAP request with a non-existing room. Thus, add the Not SOAP Fault assertion to getRoomDetails SOAP Request TestStep.

5. Run the addReservation TestCase of ReservationTestSuite again. You will get a test failure, as shown in the following screenshot:

The testRunner variable


7. The context Object

Resons for using Groovy script in SOAPUI tool:

  • To dynamically generate Mock Responses when simulating web services
  • To add arbitrary functionality to TestCases using Groovy Script TestStep
  • To use as Setup/TearDown scripts to initialize, and cleanup TestSuites and TestCases
  • To use as Start/Stop scripts in initializing/cleaning up mock services
  • To dynamically generate TestRequests and assertions based on database contents
  • The OnRequest and AfterRequest scripts in Mock Services
  • To perform arbitrary functionality during property expansion
The Groovy scripts inside soapUI have access to the following context-related variables:

1. context
2. testRunner

soapUI also provides us with a standard log4j Logger object—log—that can be used in scripts at any level in a soapUI project.

1. The Context Object

The context object holds information about a particular test run session. It can be used to read and write/update context-specific variables. There are different contexts available in a soapUI project.
For Example:

1. LoadTestRunContext: This holds context information about the load test run session.

2. MockRunContext: This context is available for the duration of a Mock Services' execution.

3. SubmitContext: This is available during one submit of a request.

4. TestRunContext: This is available during a TestCase execution and all scripts in a TestCase run have access to the TestRunContext.

The usage of the context object using a simple example:

1. Open the HotelReservation project in soapUI and add a Groovy Script TestStep into getRoomDetails TestCase. Name the test step GroovyTestScript1.

2. Add the following script in script editor and run the test step by clicking on the green arrow icon which is in the upper-left corner of the Groovy Script editor:

// Get the name of current TestStep

log.info(context.getCurrentStep().getLabel())

// Get the name of current parent TestCase
log.info(context.getTestCase().getLabel())

// Get the name of TestSuite

log.info(context.getTestCase().getTestSuite().getLabel())


// Get the name of SOAPUI project
log.info(context.getTestCase().getTestSuite().getProject().getName())

You will find the output of test run at the Log Output window which appears right below the script editor. It will look similar to the following.

Tue Feb 12 19:03:15 IST 2019:INFO:GroovytestScript1 

Tue Feb 12 19:03:15 IST 2019:INFO:getRoomDetails 

Tue Feb 12 19:03:15 IST 2019:INFO:RoomManagementServiceTestSuite 

Tue Feb 12 19:03:15 IST 2019:INFO:HotelReservationproject 


The context object is useful in situations where you want to read the property values of TestStep. 

For example:
we have a property, Endpoint, defined at getRoomDetails SOAP Request TestStep. We can simply read the value of this property using a context object, as shown in the following script:

EndPointProp =context.getProperty("getRoomDetails","Endpoint")

Note that you cannot read the property value from a TestStep of a different TestCase using this method. 
The following will return null as deleteRoom TestStep is in a different TestCase:

EndPointProp2 = context.getProperty("deleteRoom","Endpoint")

log.info(EndPointProp2)

OUTPUTWed Feb 13 11:24:35 IST 2019:INFO:null 

Now, let's do another test to find out what properties are available during a single run of a TestStep. Add the following script in the editor of Groovy Script TestStep and run the test step:

String[] props= context.getPropertyNames()
for (prop in props) {
log.info(prop)
}

Here, we read all property names of the current context into a string array and iterate over the values.  
There are three built-in properties associated with the context of request submission—ThreadIndex, log, and RunCount:

OUTPUT:   Wed Feb 13 11:30:13 IST 2019:INFO:ThreadIndex 
                    Wed Feb 13 11:30:13 IST 2019:INFO:log 
                    Wed Feb 13 11:30:13 IST 2019:INFO:RunCount 

Double-click on the getRoomDetails TestCase to open the getRoomDetails TestCase editor. Now, you will have the getRoomDetails SOAP Test request and GroovyTestScript1 TestSteps under the TestCase. Run the getRoomDetails TestCase by selecting the green arrow icon at the top of the getRoomDetails TestCase and look at the output. This time you will see 19 properties such as httpMethod, requestUri, and postMethod, which are available at the TestCase context of the run session.

In addition to the built-in properties, we can set the properties and retrieve them later during a particular test run.

PropertyVal=new String("This is a property value")
//Setting a value to property1
context.setProperty("property1", PropertyVal)
//Reading property1's value
readPropval = context.getProperty("property1") 

log.info readPropval

OUTPUTWed Feb 13 13:17:52 IST 2019:INFO:This is a property value 

The context.expand (<String>) method is a useful method, which is inherited from      the com.eviware.soapui.model.support.AbstractAdminContext base class. 

This can be used in multiple situations and the simplest usage is for accessing a custom property at a different level of a test. If we have a custom property at project level (for example, Test), then we can use the expand method to read the property value from a script which runs from the TestStep level:

log.info(context.expand( '${#Project#Test}'))

The context object is very useful if we want to store some value in one TestStep and use it in subsequent script test steps:

1. Add another GrovyScript TestStep in the getRoomDetails TestCase. Let's name it GroovyTestScript2:

2. Add the following into GroovyTestScript1 to define a new property, holder in context:

context.holder="testing"

3. Now, add the following in GroovyTestScript2 to read the property value:

holderValue = context.getProperty("holder")
log.info(holderValue)

OUTPUTWed Feb 13 19:02:15 IST 2019:INFO:testing 

Once you run the getRoomDetails TestCase, you will see the log output of GroovyTestScript2 run which prints testing as the result.
 In this example, context represented an instance of TestCaseRunContext where the context is visible inside TestCase.

6.Introduction to Groovy Script in SOAPUI

WHAT IS GROOVY?

  • Groovy is a Scripting Language which internally includes all the Java Libraries, therefore all Java related Keywords and Functions can be used in the groovy script directly.
  • Groovy is a dynamic programming language in which most of the program execution processes are done at runtime instead of compile time.
  • Groovy can be categorized into the same family of scripting languages such as Ruby, Perl, or JavaScript.
  • Groovy uses Java-like bracket syntax and most Java code is syntactically valid in Groovy. Groovy scripts run on JVM similar to Java programs, hence we do not need to install and configure additional libraries.
  • The Java Libraries come with SOAPUI and are integrated during the SOAPUI Pro Installation itself.
  • Groovy is a loosely-typed language, which means there is no need to define the data types for the variables and for the return types of the methods.
  • Groovy Script Test Step is included for custom Automation Test Script creation in SOAPUI / pro. It can be used for Functional/Load/Regression.

Let's go through some basic principles of Groovy with examples. In order to try out the simple Groovy examples that we are going to try out, you can use the following two approaches:

  • Download the latest version of Groovy binary distribution from http://groovy.codehaus.org/Download (at the time of writing, the latest stable version was Groovy 1.8). 
  • Install Groovy on your machine as per the instructions given in the official Groovy installation guide (http://groovy.codehaus.org/Installing+Groovy). Then, you can use the interactive Groovy shell to write and run the example Groovy scripts.
  • Use soapUI Groovy Script TestStep to test the sample scripts.

We will use the second approach as it minimizes the setup time and we can quickly try out some basic principles of the Groovy scripting language.

We will use a new workspace and a project in soapUI for Groovy examples as these are not a part of our sample hotel reservation project. 
1. Go to File > New workspace and add a new workspace in soapUI. Name it GroovyExamplesWorkspace.
2. Once the new workspace is created, right-click on it and add a new soapUI project. Name the project GroovyExamplesProject. 
3. We do not add an initial WSDL for the project as we are not going to test any web services using this project. 
4. Now, add a new TestSuite and a TestCase in the project. 
5. Add a new Groovy Script Test Step by right-clicking on the TestCase and selecting Add Step, then selecting Groovy Script out of the steps available in the list. 
6. Finally, we will get a Groovy Script editor, as shown in the following screenshot, where we can try out the example scripts.

What is Groovy?

Hello World with Groovy:
Let's begin with usual Hello World script. Write the following script in the Groovy Script editor.  

// print "Hello World" string in console
log.info "Hello World" 

OUTPUTHello World

Run the script by clicking on Green Arrow Icon which is at the upper left corner of the script editor.We will observe output in the SOAPUI startup console.

Variable and object declaration in Groovy:

As with any programming language, variables or objects must be declared before they are referenced by somewhere else. The variables can be declared with the keyword def, as shown in the following script:

def  name = "SOAPUI" //Declare variable name and assign value SOAPUI 

log.info name

OUTPUT: SOAPUI

To read the value of a variable, you can just prefix the variable name with $ as in Case 1 or append it as in Java (Case 2).

Case 1:
def name = "soapui"
log.info "This is $name"

OUTPUT: This is soapui

Case 2:
def name = "soapui"
log.info "This is\t" + name

OUTPUTThis is soapui

Groovy has support for two collection data types:

Lists: 
These are used to store ordered collections of data. A list can be declared as follows:

myList = [0,56,-98,345,78976]
log.info myList

OUTPUT[0,56,-98,345,78976]

The above statement declares a list object, which holds integer values. We can access a value stored in list with myList[n], where n is the index of list.

myList = [0,56,-98,345,78976]
log.info myList[3]

OUTPUT: 345

Maps: 
These store different types of data in key-value pairs. For example, consider the following script:

myMap = ["key1":"soapui", "key2":100, "key3":30.05] 
log.info myMap["key2"] // access the value assigned to "key2"

log.info myMap.key3  // another of accessing key value

OUTPUT: 100
                  30.05

Control structures in Groovy
The syntax of control structures such as "if-else", "for", and "while" are very similar to what we have in Java. Look at the following code snippet: