Sei sulla pagina 1di 13

Usare Groovy con SOAPUI per lautomazione dei test

R. Turco
Nellarticolo Realizzare un Framework di Test con SOAPUI abbiamo mostrato le potenzialit di SOAPUI. In
realt esso permette di lavorare non solo per Web Services SOAP (su http/https o su jms) ma anche quelli
REST, la cui descrizione attraverso le WADL.
SOAPUI ci permette vari scenari:
a) Simulare un servizio (Mock Service) disponendo della sola WSDL del servizio esterno al nostro
sistema e quindi ottenere risposte da esso a richieste del nostro sistema
b) Testare un nostro Web Service
Groovy ci permetter, invece, di rendere dinamici i valori marcati con ? da passare nelle request o nelle
response.
Esamineremo il caso b), in questo breve tutorial. Se possibile usiamo lultima versione disponibile di
SOAPUI.
Il Proxy
In tale caso sul vostro PC preparate la suite di Test e in remoto c il Web Service. In tal caso vi serve
eventualmente, in una azienda, settare il proxy (per andare in remoto) settando da File -> Preferences ->
Proxy Settings -> Manual (inserire tutte le info). Se, invece, il Web Service ce lavete in locale al PC per
testarlo Proxy Settings -> None.
Il Progetto
Create un nuovo progetto con New SOAP Project -> Automation-PrepaidMobileNumberInformation.
In Initial WSDL si deve mettere la url del servizio implementato che dobbiamo testare.
Ad esempio dovreste mettere la URI del servizio in:
Initial WSDL-> http://<ip>:8105/IB/services/PrepaidMobileNumberInformationQuery-v1?wsdl"
(Se invece usate un Mock Service <ip>=localhost e la porta deve essere libera altrimenti la cambiate nella
WSDL e su SOAPUI come vedremo. La URI la trovate nella WSDL del vostro servizio nella parte binding).
Tuttavia possibile che del tutorial vi interessi solo come sfruttare Groovy con SOAPUI e non di sviluppare il
servizio, allora vi consiglio di utilizzare il WSDL in APPENDICE e di testarlo prima con un tool per verificarne
la validit e che sia well-formed.
Attenzione che nel binding, per creare un Mock Service che funzioni da PC, vi conviene mettere nel WSDL il
binding a localhost.
Per cui adesso ci generiamo il Mock Service dalla WSDL e non implementiamo il servizio. Selezioniamo la
WSDL e facciamo check su Create Request e Create Test Suite e premere OK.

Ora sulla finestra Generate Test Suite selezionare Single TestCase with one Request for each Operation.
Lasciamo il nome della Test Suite che ci propone. Inoltre non volendo sviluppare il servizio dobbiamo
almeno avere il MockService. Generiamo il Mock Service come segue.
Mettendo il mouse su PrepaidMobileNumberInformationQueryBinding con tasto destro del mouse
facciamo Generate SOAP Mock Service poi in path (importante)mettiamo
/IB/services/PrepaidMobileNumberInformationQuery-v1

Mentre su port mettiamo 8086; questi valori li avremo selezionato dalla WSDL da soap:address location.
Lasciamo anche il nome proposto da SOAPUI per il Mock Service. Dovremmo avere adesso una situazione
come in figura successiva.

Ora, come detto in premessa, come se avessimo a disposizione il Servizio implementato che vogliamo
testare (il Mock Service).
Sono almeno due gli scenari che possiamo fare.
Servizio sviluppato da testare Invio ad esso di varie Richieste ed il Servizio ci d risposte
Lobiettivo in questo caso testare un servizio realizzato e deployato, per cui di interesse magari fare vari
tipi di request e aspettarci le risposte del nostro servizio posto sotto test.
In generale, come nel caso della nostra WSDL in APPENDICE, potremmo avere sia lHEADER che il BODY che
potremmo voler valorizzare dinamicamente. In tal caso possiamo mettere su vari file la parte tra
<soapenv:Body></soapenv:Body>
Lidea di avere questi pezzi di requests scritte in diversi file con nome del tipo TestX.xml dove X un
numerico (1,2,). In ognuno di esso c siolo la parte di body della request.
Sistema sviluppato che fa richieste ad un Web Service Varie Risposte dal Mock Service
Questo il caso dove abbiamo il sistema sviluppato che fa richieste ad un Web Service esterno non
sviluppato da noi, di cui disponiamo solo la WSDL e lo simuleremo con un Mock Service e siamo interessati
a ricevere dal Mock Service varie risposte con valori diversi ovvero response diverse. Possiamo anche in
questo caso usare dei file per le response.
Directory dei file request e response
Creiamo una directory GroovyTest con le due sottodirectory Requests e Responces. Qui metteremo I file
xml, con le sole parti del Body e le valorizzeremo con i valori che ci servono nel test al posto dei ?. Per
esempio mettete due file e con valori di body diversi.
Mock Service e primo scenario
Attiviamo il Mock Service per fare il primo scenario. Su PrepaidMobileNumberInformationQueryBinding
Mock Service -> doppio click e poi sulla freccia verde startare il Mock Service

Test Suite
Posizioniamoci su Test Steps(1) e con tasto destro fare Add Step -> Groovy Script. Denominarlo Groovy
Script Step 1.
Prepariamoci una request sfruttando la Request1 generata da SOAPUI (copiandola solo, in realt non serve
ma serviranno quelle delle operation) e selezioniamo solo il Body (le parti in rosso):
<soapenv:Header>
<soap:Header>
<!--Optional:-->
<soap:sourceSystem>?</soap:sourceSystem>
<!--Optional:-->
<soap:interactionDate>
<soap:Date>?</soap:Date>
<soap:Time>?</soap:Time>
</soap:interactionDate>
<!--Optional:-->
<soap:businessID>?</soap:businessID>
<!--Optional:-->
<soap:messageID>?</soap:messageID>
<!--Optional:-->
<soap:transactionID>?</soap:transactionID>
</soap:Header>
</soapenv:Header>
<soapenv:Body>
<ns:getCreditInfoRequest>
<ns:CustomerAccount>

<ns1:MobileConnectivityCFS>
<ns1:number>?</ns1:number>
</ns1:MobileConnectivityCFS>
</ns:CustomerAccount>
</ns:getCreditInfoRequest>
</soapenv:Body>

A questo punto dipende dai test che dobbiamo fare. Ci sono test dove magari i campi opzionali non
interessano valorizzati e occorre valorizzare solo gli obbligatori. Altri in cui conviene valorizzare ogni cosa.
Supponiamo di dover iniziare a fare i test solo dei campi obbligatori. Al posto del ? per le parti obbligatorie,
number in questo caso, mettiamo ad esempio 1001 e salviamo questo file nella directory requests col nome
Test1.xml, poi ne facciamo un altro col valore 2002 e lo salviamo col nome Test2.xml e cos via.
Ora passiamo al Groovy Script. Incolliamo questo codice nella finestra che si apre cliccando su Groovy
Script:
def fileList = []
new File("C: \\GroovyTest\\requests").eachFile {f ->
if (f.isFile()&& f.name.endsWith('.xml'))
{
def fileName = f.name[0..-1]
fileList.add(fileName)
log.info fileName
}
}
if (fileList.size() <1)
{
// testRunner.fail("No request files found")
}
// context.put('fileList',fileList)

Ovviamente occorre mettere il path giusto dove la vostra directory. In prima battuta facciamo funzionare
solo il log per vedere se punta alla directory giusta e trova effettivamente due file di richieste. Cliccate sulla
freccia verde del Groovy Script e dovrebbe darvi due log relativi ai file che ha trovato. Se cos
commentiamo ora listruzione di log e scommentiamo le altre due:
def fileList = []
new File("C:\\Users\\XXX\\Desktop\\Groovy\\GroovyTest\\requests").eachFile
{f ->
if (f.isFile()&& f.name.endsWith('.xml'))
{
def fileName = f.name[0..-1]
fileList.add(fileName)
// log.info fileName
}
}
if (fileList.size() <1)
{
testRunner.fail("No request files found")
}
context.put('fileList',fileList)

Ora i valori prelevati vanno inseriti nella request. Ma come?


Nella Test Suite creiamo getCreditInfo e getCreditInfo2 e spostiamoli entrambi sotto al Groovy Script (con
Move Step Down tasto destro del mouse). Questo perch devo prima prelevare i valori dai file e poi
metterli nella Request). Clicchiamo ora su getCreditInfo e su getCredititInfo2 ed eliminiamo la parte interna
a <soapenv:Body></soapenv:Body> sostituendola con:

${=new File("C:\\GroovyTest\\requests\\" + (context.get('fileList')).last()).text}

Nel getResponse e getResponse 2 possiamo mettere delle Assert per vedere se ci sono errori o cercare dei valori particolari.
Sotto getResponse ad esempio facciamo Assertions e + e scegliamo ad esempio Compliance, Status e Standards e settiamo No
SOAP Fault (vogliamo vedere che non ci sono errori). Qua si possono mettere anche altre Assertion in cascata.
Nel Mock Service mettiamo due response Response 1 e Response 2 con il return code a 1 e 2, ad esempio. giusto affinch il servizio
risponda un valore. Ovviamente dipender dai vostri test con che valore il Web Service reale deve rispondere.

Lancio della Test Suite delle Request

Sulla Test Suite con doppio click si apre la finestra a destra. Con click su freccia verde si ottiene il lancio di
tutte le request (due nel nostro caso) e la barra che si colora di verde mi indica che i test sono andati OK. Se
ci fosse stato un rosso avremmo potuto esaminare quale richiesta fosse andata in errore.
Intanto vedendo Step 3 e Step 2 si possono vedere due cose:

Le request partite la prima con 1001 e la seconda con 2002


Le response col return code a 1 e a 2 come risposta ad ogni request.

Una suite di Test fortemente incoraggiata se il numero di test elevato si guadagna molto tempo in
regressione per una anomalia etc. Il compilare dei file con editor xml estremamente facile e rapido,
predisporre SOAPUI anche di pi.
Altre possibilit sono letture dal DB di valori di interesse, introdotte come Step ordinati, etc.
Secondo scenario
Questa volta il Mock Service pu aiutarmi a simulare varie risposte quando il nostro servizio che chiama il
Mock Service.
Possiamo fare la stessa cosa di prima ma rendendo dinamiche le response questa volta mettendo i file nella
sottodirectory responces.
Lo lasciamo come esercizio al lettore.
Asserts
Come nellaltro articolo vi consiglio di usare le assert per verificare varie cose. Infine vi consiglio un
approfondimento del linguaggio Groovy.
Load Test
SOAPUI anche forte per organizzare un Load Test ovvero un test di carico. Vedi documentazione
http://www.soapui.org/Getting-Started/load-testing.html
http://www.soapui.org/load-testing/creating-and-running-loadtests.html
Database
Per il database, invece, consultare la documentazione al link:
http://www.soapui.org/jdbc/testing-jdbc-databases.html
Groovy, SOAPUI e database.
E possibile interagire col database da SOAPUI anche usando Groovy con lintenzione di automatizzare gli
step.
Si deve conoscere il tipo di database a cui connettersi e la sintassi dei comandi richiesta. Nellesempio
successivo ipotizzo il DB Oracle e una select qualunque.
Nel Groovy Script ci devono essere linee di codice del tipo:
import groovy.sql.Sql;
def con = Sql.newInstance("jdbc:oracle:thin:@<dbserver url>:<port>:<SID>", "<db user name>", "<db password>",
"oracle.jdbc.driver.OracleDriver");
def res = con.rows("SELECT sysdate FROM dual")
log.info(res[0].sysdate.toString())

con.close()

Lesempio di sopra preleva la data di sistema dalla tabella DUAL e lo stampa a log. In res cera il risultato
della query.
Altre istruzioni sql utili con SOAPUI
firstRow( sqlQuery ) : Questo metodo ritorna la prima riga della tabella della query passata in input.
Esempio
def res = sql.firstRow(SELECT * FROM TEST_TABLE WHERE USERID=12345)

Il risultato si pu accedere con res[0] o res.<column_name>


eachRow( sqlQuery, {closure} ) : Questo metodo usato per mantenere o modificare lintero whole
ResultSet basandoci su qualche condizione. Il secondo argomento un set di istruzioni che possono essere
eseguite per ogni risultato. Esempio:
sql.eachRow( SELECT * FROM TEST_TABLE WHERE USERID=12345,
{
println( it.COLUMN_1 );
println( it[2] );
} )

Le println di sopra sono, difatti, eseguite per ogni riga del ResultSet. Le Closure possono avere un qualsiasi
numero di statement. Sopra sono 2.
execute( sqlQuery ) : E usato per operazioni CRUD come INSERT/UPDATE/DELETE e non ritorna ResultSet.
Esempio
sql.execute( DELETE FROM TEST_TABLE WHERE USERID=12345 & USERNAME=SOMENAME )
sql.execute( DELETE FROM TEST_TABLE WHERE USERID = ? & USERNAME = ? ,
[ 12345, SOMENAME ] )
Il secondo metodo simile alla tecnica di sql dinamico.

SOAPUI e altre sorgenti dati


SOAPUI pu anche leggere dati da un file CSV o da un excel.
Vedi http://www.soapui.org/data-driven-tests/functional-tests.html
Integrazione con OAUTH2
Vedi http://www.soapui.org/oauth2/oauth2-overview.html
Monitoraggio
Vedi http://www.soapui.org/api-monitoring.html. Ma in questo caso occorre la versione PRO.

Conclusioni
SOAPUI adatto a Test funzionali e di carico, si integra facilmente con Web Service di tipo SOAP e REST
(compreso JMS), sia http/https, si integra con ogni tipo di database in termini jdbc, con altre fonti dati come
excel e csv. Permette lautomazione degli step con Groovy, lintegrazione con un server di autenticazione
come OAUTH2 e il Monitoraggio. Un vero Supereroe!!
Alla prossima.

APPENDICE
WSDL_PrepaidMobileNumberInformationQuery_Concrete-v1
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:nsSchema="http://telecomitalia.it/SOA/PrepaidMobileNumberInformationQuery/2010-08-05"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:head="http://telecomitalia.it/SOA/SOAP/SOAPHeader"
xmlns:tns="http://telecomitalia.it/SOA/PrepaidMobileNumberInformationQuery" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://telecomitalia.it/SOA/PrepaidMobileNumberInformationQuery">
<wsdl:types>
<xsd:schema targetNamespace="http://telecomitalia.it/SOA/PrepaidMobileNumberInformationQuery">
<xsd:import namespace="http://telecomitalia.it/SOA/PrepaidMobileNumberInformationQuery/201008-05" schemaLocation="PrepaidMobileNumberInformationQuery.xsd"/>
<xsd:import namespace="http://telecomitalia.it/SOA/SOAP/SOAPHeader"
schemaLocation="SOAPHeader_v1.1.xsd"/>
<!-- <xsd:import
namespace="http://telecomitalia.it/SOA/SOAP/SOAPHeader"schemaLocation="../../Shared/SOAPHeader_v1.1.xsd"/>-->
</xsd:schema>
</wsdl:types>
<wsdl:message name="getCreditInfoRequest">
<wsdl:part name="Header" element="head:Header"/>
<wsdl:part name="body" element="nsSchema:getCreditInfoRequest"/>
</wsdl:message>
<wsdl:message name="getCreditInfoResponse">
<wsdl:part name="Header" element="head:Header"/>
<wsdl:part name="body" element="nsSchema:getCreditInfoResponse"/>
</wsdl:message>
<wsdl:portType name="PrepaidMobileNumberInformationQueryPortType">
<wsdl:operation name="getCreditInfo">
<wsdl:input message="tns:getCreditInfoRequest"/>
<wsdl:output message="tns:getCreditInfoResponse"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="PrepaidMobileNumberInformationQueryBinding"
type="tns:PrepaidMobileNumberInformationQueryPortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="getCreditInfo">
<soap:operation soapAction="getCreditInfo" style="document"/>
<wsdl:input>
<soap:body parts="body" use="literal"/>
<soap:header message="tns:getCreditInfoRequest" part="Header" use="literal"/>
</wsdl:input>
<wsdl:output>
<soap:body parts="body" use="literal"/>
<soap:header message="tns:getCreditInfoResponse" part="Header" use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="PrepaidMobileNumberInformationQuery-v1">

<wsdl:port name="PrepaidMobileNumberInformationQuery"
binding="tns:PrepaidMobileNumberInformationQueryBinding">
<soap:address location="http://localhost:8086/IB/services/PrepaidMobileNumberInformationQueryv1"/>
<!--address location="http://10.184.67.27:12102/IB/services/PrepaidMobileNumberInformationQueryv1"/>-->
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
SOAPHeader_v1.1.xsd
<?xml version="1.0" encoding="UTF-8"?>
<!-- // FILE-ID // Name: SOAPHeader_v1.1.xsd // Version: 1.1 // Type: XSD file // Analysis Version: // Kit Version:
// Created: 05/03/2009 // Modified 16/03/2010 // Developed by: Simone Avossa-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:h="http://telecomitalia.it/SOA/SOAP/SOAPHeader"
targetNamespace="http://telecomitalia.it/SOA/SOAP/SOAPHeader" elementFormDefault="qualified" version="1.1">
<!--Start Types Definition-->
<xs:complexType name="HeaderType">
<xs:annotation>
<xs:documentation>Informazioni di contesto dell'invocazione del servizio</xs:documentation>
</xs:annotation>
<xs:sequence>
<xs:element name="sourceSystem" type="h:sourceSystemType" minOccurs="0">
<xs:annotation>
<xs:documentation>Sistema da cui proviene la richiesta</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="interactionDate" type="h:interactionDateType" minOccurs="0">
<xs:annotation>
<xs:documentation>Data e Ora di invocazione del servizio</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="businessID" type="h:businessIDType" minOccurs="0">
<xs:annotation>
<xs:documentation>Identifica univocamente il processo
dibusiness</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="messageID" type="h:messageIDType" minOccurs="0">
<xs:annotation>
<xs:documentation>Identifica il messaggio in maniera univoca</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="transactionID" type="h:transactionIDType" minOccurs="0">
<xs:annotation>
<xs:documentation>Identifica la transazione per gestire i ritornisincroni
</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
<xs:simpleType name="dateType">
<xs:restriction base="xs:string">
<xs:pattern value=" \d{4}-\d{2}-\d{2}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="timeType">
<xs:restriction base="xs:string">
<xs:pattern value=" \d{2}:\d{2}:\d{2}((Z)|(\.\d{1,}Z?)|((\+|-)\d{2}:\d{2}))?"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="businessIDType">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="messageIDType">

<xs:restriction base="xs:string">
<xs:minLength value="1"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="sourceSystemType">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="transactionIDType">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="interactionDateType">
<xs:sequence>
<xs:element name="Date" type="h:dateType">
<xs:annotation>
<xs:documentation>Per compatibilit con i diversi prodotti o librerie software
(es.Axis2 e BW) si scelto di utilizzare il tipo string. La restizione applicata accetta il formato: CCYY-MM-DD. Non sono presenti
restrizionisul range dei valori.</xs:documentation>
</xs:annotation>
</xs:element>
<xs:element name="Time" type="h:timeType">
<xs:annotation>
<xs:documentation>Per compatibilit con i diversi prodotti o librerie software
(es.Axis2 e BW) si scelto di utilizzare il tipo string. La restizione applicata accetta il formato: hh:mm:ss.sss. Non sono presenti
restrizioni sul range dei valori. Per gli ulteriori dettagli sul formato fare riferimento alla definizione di Time Data Type W3C,
presente al link:http://www.w3schools.com/Schema/schema_dtypes_date.asp
</xs:documentation>
</xs:annotation>
</xs:element>
</xs:sequence>
</xs:complexType>
<!--End Types Definition-->
<xs:element name="Header" type="h:HeaderType"/>
</xs:schema>

PrepaidMobileNumberInformationQuery.xsd

<?xml version="1.0" encoding="UTF-8"?>


<!-- //-FILE-ID // Name: MobileCreditQuery.xsd // Version: 1.0 // Type: XSD file // Analysis
Version:SIF_PrepaidMobileNumberInformationQuery-v1.0.doc
// Kit Version: Kit_2011_KS4 // Created: 2010-01-28 // Modified: // Developed by: T.IT.SC.SOA-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:sm="http://telecomitalia.it/SOA/PrepaidMobileNumberInformationQuery/2010-08-05"
xmlns:cst="http://telecomitalia.it/SOA/PrepaidMobileNumberInformationQueryCustomTypes/2010-08-05"
targetNamespace="http://telecomitalia.it/SOA/PrepaidMobileNumberInformationQuery/2010-08-05"
elementFormDefault="qualified" version="1.0">
<xs:import namespace="http://telecomitalia.it/SOA/PrepaidMobileNumberInformationQueryCustomTypes/2010-08-05"
schemaLocation="PrepaidMobileNumberInformationQueryEntities.xsd"/>
<!--getCreditInfo START-->
<xs:element name="getCreditInfoRequest">
<xs:complexType>
<xs:sequence>
<xs:element name="CustomerAccount" type="cst:CustomerAccountWithConnectivityCFS"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="getCreditInfoResponse">
<xs:complexType>
<xs:sequence>
<xs:element name="ProcessData" type="sm:ProcessData"/>
<xs:element name="CustomerAccount" type="cst:CustomerAccountWithCredit"
minOccurs="0"/>
</xs:sequence>

</xs:complexType>
</xs:element>
<!--getCreditInfo END-->
<!--ComplexTypes START-->
<xs:complexType name="ProcessData">
<xs:sequence>
<xs:element name="returnCode" type="sm:noEmptyFieldType"/>
<xs:element name="returnDescription" type="sm:noEmptyFieldType" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<!--ComplexTypes END-->
<!--SimpleTypes START-->
<xs:simpleType name="noEmptyFieldType">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="dateType">
<xs:restriction base="xs:date"/>
</xs:simpleType>
<!--SimpleTypes END-->
</xs:schema>

PrepaidMobileNumberInformationQueryEntities.xsd

<?xml version="1.0" encoding="UTF-8"?>


<!-- //-FILE-ID // Name: MobileCreditQueryEntities.xsd // Version: 1.0 // Type: XSD file
// Analysis Version: SIF_MobileCreditQuery-v1.0.doc
// Kit Version: Kit_2011_KS4 // Created: 2010-01-28 // Modified: // Developed by: T.IT.SC.SOA-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:bvi="http://telecomitalia.it/SOA/BVI"
xmlns:cst="http://telecomitalia.it/SOA/PrepaidMobileNumberInformationQueryCustomTypes/2010-08-05"
targetNamespace="http://telecomitalia.it/SOA/PrepaidMobileNumberInformationQueryCustomTypes/2010-08-05"
elementFormDefault="qualified" version="1.0">
<!--Entities START-->
<!--CustomerFacingService START-->
<xs:complexType name="MobileConnectivityCFS">
<xs:sequence>
<xs:element name="number" type="cst:telephoneNumberType"/>
</xs:sequence>
</xs:complexType>
<!--CustomerFacingService END-->
<!--Customer START-->
<xs:complexType name="CustomerAccountWithConnectivityCFS">
<xs:sequence>
<xs:element name="MobileConnectivityCFS" type="cst:MobileConnectivityCFS"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="CustomerAccountWithCredit">
<xs:sequence>
<xs:element name="creditAmount" type="cst:decimalType"/>
<xs:element name="creditDate" type="cst:dateTimeType" minOccurs="0"/>
<xs:element name="lastTopUpDate" type="cst:dateTimeType" minOccurs="0"/>
<xs:element name="creditValidFor" type="cst:TimePeriod" minOccurs="0"/>
<xs:element name="Product" type="cst:Product" minOccurs="0"/>
<xs:element name="MobileConnectivityCFS" type="cst:MobileConnectivityCFS"/>
</xs:sequence>
</xs:complexType>
<!--Customer END-->
<!--Product START-->
<xs:complexType name="Product">
<xs:sequence>
<xs:element name="ProductOffering" type="cst:ProductOffering"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ProductOffering">

<xs:sequence>
<xs:element name="id" type="cst:noCommonConstraintsType"/>
</xs:sequence>
</xs:complexType>
<!--Product END-->
<!--BaseTypes START-->
<xs:complexType name="TimePeriod">
<xs:sequence>
<xs:element name="endDateTime" type="cst:dateTimeType"/>
</xs:sequence>
</xs:complexType>
<!--BaseTypes END-->
<!--Entities END-->
<!--CommonTypes START-->
<xs:simpleType name="telephoneNumber">
<xs:annotation>
<xs:appinfo>
<bvi:primitiveType>
<bvi:className>TelephoneNumber</bvi:className>
</bvi:primitiveType>
</xs:appinfo>
</xs:annotation>
<xs:restriction base="xs:string">
<xs:pattern value=" \+?\d{1,}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="decimal">
<xs:annotation>
<xs:appinfo>
<bvi:primitiveType>
<bvi:className>Decimal</bvi:className>
</bvi:primitiveType>
</xs:appinfo>
</xs:annotation>
<xs:restriction base="xs:decimal"/>
</xs:simpleType>
<xs:simpleType name="dateTime">
<xs:annotation>
<xs:appinfo>
<bvi:primitiveType>
<bvi:className>DateTime</bvi:className>
</bvi:primitiveType>
</xs:appinfo>
</xs:annotation>
<xs:restriction base="xs:dateTime"/>
</xs:simpleType>
<!--CommonTypes END-->
<!--SimpleTypes START-->
<xs:simpleType name="telephoneNumberType">
<xs:restriction base="cst:telephoneNumber">
<xs:pattern value=" \d{1,}"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="decimalType">
<xs:restriction base="cst:decimal"/>
</xs:simpleType>
<xs:simpleType name="dateTimeType">
<xs:restriction base="cst:dateTime"/>
</xs:simpleType>
<xs:simpleType name="noCommonConstraintsType" final="#all">
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
</xs:restriction>
</xs:simpleType>
<!--SimpleTypes END-->
</xs:schema>