├── .github
└── workflows
│ └── python-app.yml
├── .gitignore
├── Doc
├── SoapLibrary.html
├── SoapLibrary.xml
├── img2_SoapLibrary.png
└── img_SoapUI.png
├── LICENSE.md
├── README.md
├── SoapLibrary
├── SoapLibrary.py
├── __init__.py
├── config.py
└── version.py
├── Tests
├── Requests
│ ├── New_Request.xml
│ ├── New_Request_Calculator.xml
│ ├── Request_Calculator.xml
│ ├── Request_Calculator_500.xml
│ ├── busca_servicos.xml
│ ├── consultaCEP.xml
│ ├── request.xml
│ └── request_capital.xml
└── keyword_tests.robot
├── dist
├── robotframework-soaplibrary-0.8.tar.gz
├── robotframework-soaplibrary-0.9.tar.gz
├── robotframework-soaplibrary-1.0.tar.gz
├── robotframework-soaplibrary-1.2.tar.gz
└── robotframework-soaplibrary-1.3.tar.gz
├── examples
├── request
│ ├── cep.xml
│ └── ip.xml
└── samples.robot
├── requirements.txt
├── robotframework_soaplibrary.egg-info
├── PKG-INFO
├── SOURCES.txt
├── dependency_links.txt
├── requires.txt
└── top_level.txt
└── setup.py
/.github/workflows/python-app.yml:
--------------------------------------------------------------------------------
1 | name: SOAP-Library
2 |
3 | on:
4 | push:
5 | branches:
6 | - 'test/**'
7 | pull_request:
8 | branches:
9 | - master
10 |
11 | jobs:
12 | run-robot-tests:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/checkout@v4
16 | - name: Set up Python 3.10
17 | uses: actions/setup-python@v4
18 | env:
19 | ROBOT_TESTS_DIR: ${{ github.workspace }}/Tests
20 | ROBOT_REPORTS_DIR: ${{ github.workspace }}/reports
21 | with:
22 | python-version: '3.10'
23 | - name: Install Dependencies
24 | run: pip install -r requirements.txt
25 | - name: Run Robot File
26 | run: robot -d ./reports -e offline ./Tests/keyword_tests.robot
27 | - name: Upload test results
28 | uses: actions/upload-artifact@v1
29 | if: always()
30 | with:
31 | name: robot_reports
32 | path: reports
33 |
34 | generate-robot-report:
35 | if: always()
36 | needs: [run-robot-tests]
37 | runs-on: ubuntu-latest
38 | steps:
39 | - name: Download reports
40 | uses: actions/download-artifact@v1
41 | with:
42 | name: robot_reports
43 | - name: Send report to commit
44 | uses: joonvena/robotframework-reporter-action@v2.4
45 | with:
46 | gh_access_token: ${{ secrets.GITHUB_TOKEN }}
47 | report_path: /robot_reports
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 |
3 | # Byte-compiled / optimized / DLL files
4 | __pycache__/
5 | *.py[cod]
6 | response_test.xml
7 | report.html
8 | output.xml
9 | log.html
10 |
--------------------------------------------------------------------------------
/Doc/SoapLibrary.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 1.3
4 | SoapLibrary is a library for testing SOAP-based web services.
5 |
6 | SoapLibrary is based on [https://python-zeep.readthedocs.io/en/master/|Zeep], a modern SOAP client for Python.
7 |
8 | This library is designed for those who want to work with webservice automation as if they were using SoapUI,
9 | make a request through an XML file, and receive the response in another XML file.
10 |
11 | = Example =
12 |
13 | | ***** Settings *****
14 | | Library SoapLibrary
15 | | Library OperatingSystem
16 | |
17 | | ***** Test Cases *****
18 | | Simple Example
19 | | Create Soap Client http://endpoint.com/example.asmx?wsdl
20 | | ${response} Call SOAP Method Method_name arg1 arg2
21 | | Log ${response}
22 | |
23 | | Example With XML
24 | | Create Soap Client http://endpoint.com/example.asmx?wsdl
25 | | ${response} Call SOAP Method With XML ${CURDIR}/request.xml
26 | | ${text} Get Data From XML By Tag ${response} tag_name
27 | | Log ${text}
28 | | Save XML To File ${response} ${CURDIR} response_test
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | name
38 |
39 |
40 | args
41 |
42 |
43 | status
44 | None
45 |
46 |
47 | If the webservice have simple SOAP operation/method with few arguments, you can call the method with the given
48 | `name` and `args`.
49 |
50 | The first argument of the keyword ``name`` is the operation name of the ``SOAP operation/method``
51 | [https://www.soapui.org/soap-and-wsdl/operations-and-requests.html|More information here]
52 |
53 | By default, this keyword fails if a status code different from 200 is returned as response,
54 | this behavior can be modified using the argument status=anything.
55 |
56 | *Input Arguments:*
57 | | *Name* | *Description* |
58 | | name | Name of the SOAP operation/method |
59 | | args | List of request entries |
60 | | status | if set as anything, return the error as a string |
61 |
62 | Note, this keyword uses the most basic method of sending a request, through zeep that creates the xml based
63 | on the wsdl definition. So this keyword does not store the response object, and therefore it is not possible
64 | to use the keyword `Get Last Response Object` after this one.
65 |
66 | *Example:*
67 | | ${response}= | Call SOAP Method | operation_name | arg1 | arg2 |
68 | | ${response}= | Call SOAP Method | operation_name | arg1 | arg2 | status=anything |
69 | If the webservice have simple SOAP operation/method with few arguments, you can call the method with the given `name` and `args`.
70 |
71 |
72 |
73 |
74 | string_xml
75 |
76 |
77 | headers
78 | {'Content-Type': 'text/xml; charset=utf-8'}
79 |
80 |
81 | status
82 | None
83 |
84 |
85 | Send a string representation of XML as a request to the SOAP client.
86 | The SOAP method is inside the XML string.
87 |
88 | By default, this keyword fails if a status code different from 200 is returned as response,
89 | this behavior can be modified using the argument status=anything.
90 |
91 | *Input Arguments:*
92 | | *Name* | *Description* |
93 | | string_xml | string representation of XML |
94 | | headers | dictionary with request headers. Default ``{'Content-Type': 'text/xml; charset=utf-8'}`` |
95 | | status | optional string: anything |
96 |
97 | *Example:*
98 | | ${response}= | Call SOAP Method With String XML | "<sample><Id>1</Id></sample>" |
99 | | ${response}= | Call SOAP Method With String XML | "<sample><Id>error</Id></sample>" | status=anything |
100 | Send a string representation of XML as a request to the SOAP client. The SOAP method is inside the XML string.
101 |
102 |
103 |
104 |
105 | xml
106 |
107 |
108 | headers
109 | {'Content-Type': 'text/xml; charset=utf-8'}
110 |
111 |
112 | status
113 | None
114 |
115 |
116 | Send an XML file as a request to the SOAP client. The path to the Request XML file is required as argument,
117 | the SOAP method is inside the XML file.
118 |
119 | By default, this keyword fails if a status code different from 200 is returned as response,
120 | this behavior can be modified using the argument status=anything.
121 |
122 | *Input Arguments:*
123 | | *Name* | *Description* |
124 | | xml | file path to xml file |
125 | | headers | dictionary with request headers. Default ``{'Content-Type': 'text/xml; charset=utf-8'}`` |
126 | | status | optional string: anything |
127 |
128 | *Example:*
129 | | ${response}= | Call SOAP Method With XML | ${CURDIR}${/}Request.xml |
130 | | ${response}= | Call SOAP Method With XML | ${CURDIR}${/}Request_status_500.xml | status=anything |
131 | Send an XML file as a request to the SOAP client. The path to the Request XML file is required as argument, the SOAP method is inside the XML file.
132 |
133 |
134 |
135 |
136 | xml_etree
137 |
138 |
139 | Convert the webservice response into a dictionary.
140 |
141 | *Input Arguments:*
142 | | *Name* | *Description* |
143 | | xml_etree | etree object of the xml to convert to dictionary |
144 |
145 | *Example:*
146 | | ${response}= | Call SOAP Method With XML | ${CURDIR}${/}Request.xml |
147 | | ${dict_response}= | Convert XML Response to Dictionary | ${response} |
148 | Convert the webservice response into a dictionary.
149 |
150 |
151 |
152 |
153 | url
154 |
155 |
156 | ssl_verify
157 | True
158 |
159 |
160 | client_cert
161 | None
162 |
163 |
164 | auth
165 | None
166 |
167 |
168 | use_binding_address
169 | False
170 |
171 |
172 | Loads a WSDL from the given ``url`` and creates a Zeep client.
173 | List all Available operations/methods with INFO log level.
174 |
175 | By default, server TLS certificate is validated. You can disable this behavior by setting ``ssl_verify``
176 | to ``False`` (not recommended!). If your host uses a self-signed certificate, you can also pass the path of the
177 | CA_BUNDLE to ``sll_verify``. Accepted are only X.509 ASCII files (file extension .pem, sometimes .crt).
178 | If you have two different files for root and intermediate certificate, you must combine them manually into one.
179 |
180 | If your host requires client certificate based authentication, you can pass the
181 | path to your client certificate to the ``client_cert`` argument.
182 |
183 | For HTTP Basic Authentication, you can pass the list with username and password
184 | to the ``auth`` parameter.
185 |
186 | If you want to use the binding address in the requests, you need to pass use_binding_address=True in
187 | the argument.
188 |
189 | *Example:*
190 | | Create SOAP Client | http://endpoint.com?wsdl |
191 | | Create SOAP Client | https://endpoint.com?wsdl | ssl_verify=True |
192 | | Create SOAP Client | https://endpoint.com?wsdl | use_binding_address=True |
193 | | Create SOAP Client | https://endpoint.com?wsdl | client_cert=${CURDIR}${/}mycert.pem |
194 | | ${auth} | Create List | username | password |
195 | | Create SOAP Client | https://endpoint.com?wsdl | auth=${auth} |
196 | Loads a WSDL from the given ``url`` and creates a Zeep client. List all Available operations/methods with INFO log level.
197 |
198 |
199 |
200 |
201 | response
202 |
203 |
204 | Decodes texts that are base64 encoded.
205 |
206 | Returns the decoded response.
207 |
208 | *Input Arguments:*
209 | | *Name* | *Description* |
210 | | response | Response of the webservice coded in base64 |
211 |
212 | *Example:*
213 | | ${response}= | Call SOAP Method With XML | ${CURDIR}${/}Request.xml |
214 | | ${response_decoded}= | Decode Base64 | ${response} |
215 | Decodes texts that are base64 encoded.
216 |
217 |
218 |
219 |
220 | xml_file_path
221 |
222 |
223 | new_values_dict
224 |
225 |
226 | edited_request_name
227 |
228 |
229 | repeated_tags
230 | All
231 |
232 |
233 | Changes a field on the given XML to a new given value, the values must be in a dictionary xml_filepath must be
234 | a "template" of the request to the webservice. new_values_dict must be a dictionary with the keys
235 | and values to change. request_name will be the name of the new XMl file generated with the changed request.
236 |
237 | If there is a tag that appears more than once, all occurrences will be replaced by the new value by default.
238 | If you want to change a specific tag, inform the occurrence number in the repeated_tags argument.
239 |
240 | Returns the file path of the new Request file.
241 |
242 | *Input Arguments:*
243 | | *Name* | *Description* |
244 | | xml_file_path | file path to xml file |
245 | | new_values_dict | dictionary with tags as keys and tag value as value |
246 | | edited_request_name | name of the new XMl file generated with the changed request |
247 | | repeated_tags | Occurrence number of the repeated tag to change value |
248 |
249 | *Example*:
250 | | ${dict}= | Create Dictionary | tag_name1=SomeText | tag_name2=OtherText |
251 | | ${xml_edited}= | Edit XML Request | request_filepath | ${dict} | New_Request |
252 | | ${xml_edited}= | Edit XML Request | request_filepath | ${dict} | New_Request | repeated_tags=0 |
253 | Changes a field on the given XML to a new given value, the values must be in a dictionary xml_filepath must be a "template" of the request to the webservice. new_values_dict must be a dictionary with the keys and values to change. request_name will be the name of the new XMl file generated with the changed request.
254 |
255 |
256 |
257 |
258 | xml
259 |
260 |
261 | tag
262 |
263 |
264 | index
265 | 1
266 |
267 |
268 | Gets data from XML using a given tag.
269 | If the tag returns zero or more than one result, it will show a warning. The xml argument must be an
270 | etree object, can be used with the return of the keyword `Call SOAP Method With XML`.
271 |
272 | Returns the string representation of the value.
273 |
274 | *Input Arguments:*
275 | | *Name* | *Description* |
276 | | xml | xml etree object |
277 | | tag | tag to get value from |
278 | | index | tag index if there are multiple tags with the same name, starting at 1. Default is set to 1 |
279 |
280 | *Examples:*
281 | | ${response}= | Call SOAP Method With XML | ${CURDIR}${/}Request.xml |
282 | | ${value}= | Get Data From XML By Tag | ${response} | SomeTag |
283 | | ${value}= | Get Data From XML By Tag | ${response} | SomeTag | index=9 |
284 | Gets data from XML using a given tag. If the tag returns zero or more than one result, it will show a warning. The xml argument must be an etree object, can be used with the return of the keyword `Call SOAP Method With XML`.
285 |
286 |
287 |
288 |
289 | Gets the response object from the last request made. With the object in a variable, you can use the
290 | dot operator to get all the attributes of the response.
291 |
292 | Response object attributes:
293 | | apparent_encoding |
294 | | close |
295 | | connection |
296 | | content |
297 | | cookies |
298 | | elapsed |
299 | | encoding |
300 | | headers |
301 | | history |
302 | | is_permanent_redirect |
303 | | is_redirect |
304 | | iter_content |
305 | | iter_lines |
306 | | json |
307 | | links |
308 | | next |
309 | | ok |
310 | | raise_for_status |
311 | | raw |
312 | | reason |
313 | | request |
314 | | status_code |
315 | | text |
316 | | url |
317 |
318 | Note, this keyword only works after the execution of `Call SOAP Method With XML` or
319 | `Call SOAP Method With String XML`.
320 |
321 | *Example:*
322 | | ${response}= | Call SOAP Method With XML | ${CURDIR}${/}Request.xml |
323 | | ${response_object}= | Get Last Response Object |
324 | | ${response_header}= | Set Variable | ${response_object.headers} |
325 | | ${response_status}= | Set Variable | ${response_object.status_code} |
326 | Gets the response object from the last request made. With the object in a variable, you can use the dot operator to get all the attributes of the response.
327 |
328 |
329 |
330 |
331 | etree_xml
332 |
333 |
334 | save_folder
335 |
336 |
337 | file_name
338 |
339 |
340 | Save the webservice response as an XML file.
341 |
342 | Returns the file path of the newly created xml file.
343 |
344 | *Input Arguments:*
345 | | *Name* | *Description* |
346 | | etree_xml | etree object of the xml |
347 | | save_folder | directory to save the new file |
348 | | file_name | name of the new xml file without .xml |
349 |
350 | *Example*:
351 | | ${response}= | Call SOAP Method With XML | ${CURDIR}${/}Request.xml |
352 | | ${response_file}= | Save XML To File | ${response} | ${CURDIR} | response_file_name |
353 | Save the webservice response as an XML file.
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
--------------------------------------------------------------------------------
/Doc/img2_SoapLibrary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarketSquare/Robot-Framework-SOAP-Library/4c0a37b4b1f789765dae3808f81ab40535f1c0d6/Doc/img2_SoapLibrary.png
--------------------------------------------------------------------------------
/Doc/img_SoapUI.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarketSquare/Robot-Framework-SOAP-Library/4c0a37b4b1f789765dae3808f81ab40535f1c0d6/Doc/img_SoapUI.png
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 altranpt
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://pypi.org/project/robotframework-soaplibrary)
2 | [](https://pypi.org/project/robotframework-soaplibrary)
3 | [](https://pypi.org/project/robotframework-soaplibrary)
4 | [](https://github.com/MarketSquare/Robot-Framework-SOAP-Library/actions/workflows/python-app.yml)
5 |
6 |
7 | # Robot-Framework-SOAP-Library
8 | SOAP Library for Robot Framework
9 |
10 | ## Compatibility
11 | - _Python 3.7 +_
12 | - _Zeep 4.2.1 +_
13 |
14 | ## Introduction
15 | The SoapLibrary was created for those who want to use the Robot Framework as if they were using SoapUI, just send the request XML and get the response XML.
16 |
17 | 
18 |
19 | 
20 |
21 | ## Instalation
22 | For the first time installation:
23 | ```commandline
24 | pip install robotframework-soaplibrary
25 | ```
26 | Or you can upgrade with:
27 | ```commandline
28 | pip install --upgrade robotframework-soaplibrary
29 | ```
30 |
31 | ## Example
32 |
33 | ```RobotFramework
34 | *** Settings ***
35 | Library SoapLibrary
36 | Library OperatingSystem
37 |
38 | *** Test Cases ***
39 | Example
40 | Create Soap Client http://endpoint.com/example.asmx?wsdl
41 | ${response} Call SOAP Method With XML ${CURDIR}/request.xml
42 | ${text} Get Data From XML By Tag ${response} tag_name
43 | Log ${text}
44 | Save XML To File ${response} ${CURDIR} response_test
45 | ```
46 |
47 | ## Example with certificate
48 |
49 | You can see [here](https://michaelhallik.github.io/blog/2022/04/10/Using-OpenSSL-to-provide-the-RF-SoapLibrary-with-a-TLS-client-certificate) an example of how to use OPENSSL to access a webservice with TLS certificate. (Thanks Michael Hallik)
50 |
51 | ## Keyword Documentation
52 |
53 | You can find the keywords documentation [here](https://raw.githack.com/MarketSquare/Robot-Framework-SOAP-Library/master/Doc/SoapLibrary.html)
54 |
55 | ## Authors
56 | Initial development was sponsored by [Capgemini Engineering](https://www.capgemini.com/about-us/who-we-are/our-brands/capgemini-engineering/)
57 | - **Samuel Cabral**
58 | - **Joao Gomes**
59 |
60 | ## License
61 | This project is licensed under the MIT License - see the [LICENSE.md](https://github.com/MarketSquare/Robot-Framework-SOAP-Library/blob/master/LICENSE.md) file for details.
62 |
--------------------------------------------------------------------------------
/SoapLibrary/SoapLibrary.py:
--------------------------------------------------------------------------------
1 | import os
2 | import logging.config
3 | import warnings
4 | import base64
5 | from .config import DICT_CONFIG
6 | from requests import Session
7 | from requests.auth import HTTPBasicAuth
8 | from zeep import Client
9 | from zeep.transports import Transport
10 | from zeep.wsdl.utils import etree
11 | from robot.api import logger
12 | from robot.api.deco import keyword
13 | from urllib3.exceptions import InsecureRequestWarning
14 | from .version import VERSION
15 |
16 | logging.config.dictConfig(DICT_CONFIG)
17 | # hide unnecessary warnings
18 | warnings.simplefilter("ignore", InsecureRequestWarning)
19 | logging.getLogger("urllib3").setLevel(logging.WARNING)
20 |
21 | DEFAULT_HEADERS = {'Content-Type': 'text/xml; charset=utf-8'}
22 |
23 |
24 | class SoapLibrary:
25 | ROBOT_LIBRARY_SCOPE = 'TEST SUITE'
26 | ROBOT_LIBRARY_VERSION = VERSION
27 |
28 | def __init__(self):
29 | self.client = None
30 | self.url = None
31 | self.response_obj = None
32 |
33 | @keyword("Create SOAP Client")
34 | def create_soap_client(self, url, ssl_verify=True, client_cert=None, auth=None, use_binding_address=False):
35 | """
36 | Loads a WSDL from the given ``url`` and creates a Zeep client.
37 | List all Available operations/methods with INFO log level.
38 |
39 | By default, server TLS certificate is validated. You can disable this behavior by setting ``ssl_verify``
40 | to ``False`` (not recommended!). If your host uses a self-signed certificate, you can also pass the path of the
41 | CA_BUNDLE to ``sll_verify``. Accepted are only X.509 ASCII files (file extension .pem, sometimes .crt).
42 | If you have two different files for root and intermediate certificate, you must combine them manually into one.
43 |
44 | If your host requires client certificate based authentication, you can pass the
45 | path to your client certificate to the ``client_cert`` argument.
46 |
47 | For HTTP Basic Authentication, you can pass the list with username and password
48 | to the ``auth`` parameter.
49 |
50 | If you want to use the binding address in the requests, you need to pass use_binding_address=True in
51 | the argument.
52 |
53 | *Example:*
54 | | Create SOAP Client | http://endpoint.com?wsdl |
55 | | Create SOAP Client | https://endpoint.com?wsdl | ssl_verify=True |
56 | | Create SOAP Client | https://endpoint.com?wsdl | use_binding_address=True |
57 | | Create SOAP Client | https://endpoint.com?wsdl | client_cert=${CURDIR}${/}mycert.pem |
58 | | ${auth} | Create List | username | password |
59 | | Create SOAP Client | https://endpoint.com?wsdl | auth=${auth} |
60 | """
61 | self.url = url
62 | session = Session()
63 | session.verify = ssl_verify
64 | session.cert = client_cert
65 | session.auth = HTTPBasicAuth(*auth) if auth else None
66 | self.client = Client(self.url, transport=Transport(session=session))
67 | logger.info('Connected to: %s' % self.client.wsdl.location)
68 | info = self.client.service.__dict__
69 | operations = info["_operations"]
70 | logger.info('Available operations: %s' % list(operations))
71 | if use_binding_address:
72 | self.url = self.client.service._binding_options['address']
73 |
74 | @keyword("Call SOAP Method With XML")
75 | def call_soap_method_xml(self, xml, headers=DEFAULT_HEADERS, status=None):
76 | """
77 | Send an XML file as a request to the SOAP client. The path to the Request XML file is required as argument,
78 | the SOAP method is inside the XML file.
79 |
80 | By default, this keyword fails if a status code different from 200 is returned as response,
81 | this behavior can be modified using the argument status=anything.
82 |
83 | *Input Arguments:*
84 | | *Name* | *Description* |
85 | | xml | file path to xml file |
86 | | headers | dictionary with request headers. Default ``{'Content-Type': 'text/xml; charset=utf-8'}`` |
87 | | status | optional string: anything |
88 |
89 | *Example:*
90 | | ${response}= | Call SOAP Method With XML | ${CURDIR}${/}Request.xml |
91 | | ${response}= | Call SOAP Method With XML | ${CURDIR}${/}Request_status_500.xml | status=anything |
92 | """
93 | raw_text_xml = self._convert_xml_to_raw_text(xml)
94 | xml_obj = etree.fromstring(raw_text_xml)
95 | response = self.client.transport.post_xml(address=self.url, envelope=xml_obj, headers=headers)
96 | self._save_response_object(response)
97 | etree_response = self._parse_from_unicode(response.text)
98 | self._check_and_print_response(response, etree_response, status)
99 | return etree_response
100 |
101 | @keyword("Get Data From XML By Tag")
102 | def get_data_from_xml_tag(self, xml, tag, index=1):
103 | """
104 | Gets data from XML using a given tag.
105 | If the tag returns zero or more than one result, it will show a warning. The xml argument must be an
106 | etree object, can be used with the return of the keyword `Call SOAP Method With XML`.
107 |
108 | Returns the string representation of the value.
109 |
110 | *Input Arguments:*
111 | | *Name* | *Description* |
112 | | xml | xml etree object |
113 | | tag | tag to get value from |
114 | | index | tag index if there are multiple tags with the same name, starting at 1. Default is set to 1 |
115 |
116 | *Examples:*
117 | | ${response}= | Call SOAP Method With XML | ${CURDIR}${/}Request.xml |
118 | | ${value}= | Get Data From XML By Tag | ${response} | SomeTag |
119 | | ${value}= | Get Data From XML By Tag | ${response} | SomeTag | index=9 |
120 | """
121 | new_index = index - 1
122 | xpath = self._parse_xpath(tag)
123 | data_list = xml.xpath(xpath)
124 | if isinstance(data_list, (float, int)):
125 | return int(data_list)
126 | if len(data_list) == 0:
127 | logger.warn('The search "%s" did not return any result! Please confirm the tag!' % xpath)
128 | elif len(data_list) > 1:
129 | logger.debug('The tag you entered found %s items, returning the text in the index '
130 | 'number %s, if you want a different index inform the argument index=N' % (len(data_list), index))
131 | return data_list[new_index].text
132 |
133 | @keyword("Edit XML Request")
134 | def edit_xml(self, xml_file_path, new_values_dict, edited_request_name, repeated_tags='All'):
135 | """
136 | Changes a field on the given XML to a new given value, the values must be in a dictionary xml_filepath must be
137 | a "template" of the request to the webservice. new_values_dict must be a dictionary with the keys
138 | and values to change. request_name will be the name of the new XMl file generated with the changed request.
139 |
140 | If there is a tag that appears more than once, all occurrences will be replaced by the new value by default.
141 | If you want to change a specific tag, inform the occurrence number in the repeated_tags argument.
142 |
143 | Returns the file path of the new Request file.
144 |
145 | *Input Arguments:*
146 | | *Name* | *Description* |
147 | | xml_file_path | file path to xml file |
148 | | new_values_dict | dictionary with tags as keys and tag value as value |
149 | | edited_request_name | name of the new XMl file generated with the changed request |
150 | | repeated_tags | Occurrence number of the repeated tag to change value |
151 |
152 | *Example*:
153 | | ${dict}= | Create Dictionary | tag_name1=SomeText | tag_name2=OtherText |
154 | | ${xml_edited}= | Edit XML Request | request_filepath | ${dict} | New_Request |
155 | | ${xml_edited}= | Edit XML Request | request_filepath | ${dict} | New_Request | repeated_tags=0 |
156 | """
157 | string_xml = self._convert_xml_to_raw_text(xml_file_path)
158 | xml = self._convert_string_to_xml(string_xml)
159 | if not isinstance(new_values_dict, dict):
160 | raise Exception("new_values_dict argument must be a dictionary")
161 | for key, value in new_values_dict.items():
162 | if len(xml.xpath(self._replace_xpath_by_local_name(key))) == 0:
163 | logger.warn('Tag "%s" not found' % key)
164 | continue
165 | xml_xpath = self._replace_xpath_by_local_name(key)
166 | count = int(xml.xpath(("count(%s)" % xml_xpath)))
167 | logger.debug("Found %s tags with xpath %s" % (str(count), xml_xpath))
168 | if repeated_tags == 'All' or count < 2:
169 | for i in range(count):
170 | xml.xpath(xml_xpath)[i].text = value
171 | else:
172 | xml.xpath(xml_xpath)[int(repeated_tags)].text = value
173 | # Create new file with replaced request
174 | new_file_path = self._save_to_file(os.path.dirname(xml_file_path), edited_request_name, etree.tostring(xml))
175 | return new_file_path
176 |
177 | @keyword("Save XML To File")
178 | def save_xml_to_file(self, etree_xml, save_folder, file_name):
179 | """
180 | Save the webservice response as an XML file.
181 |
182 | Returns the file path of the newly created xml file.
183 |
184 | *Input Arguments:*
185 | | *Name* | *Description* |
186 | | etree_xml | etree object of the xml |
187 | | save_folder | directory to save the new file |
188 | | file_name | name of the new xml file without .xml |
189 |
190 | *Example*:
191 | | ${response}= | Call SOAP Method With XML | ${CURDIR}${/}Request.xml |
192 | | ${response_file}= | Save XML To File | ${response} | ${CURDIR} | response_file_name |
193 | """
194 | new_file_path = self._save_to_file(save_folder, file_name, etree.tostring(etree_xml, pretty_print=True))
195 | return new_file_path
196 |
197 | @keyword("Convert XML Response to Dictionary")
198 | def convert_response_dict(self, xml_etree):
199 | """
200 | Convert the webservice response into a dictionary.
201 |
202 | *Input Arguments:*
203 | | *Name* | *Description* |
204 | | xml_etree | etree object of the xml to convert to dictionary |
205 |
206 | *Example:*
207 | | ${response}= | Call SOAP Method With XML | ${CURDIR}${/}Request.xml |
208 | | ${dict_response}= | Convert XML Response to Dictionary | ${response} |
209 | """
210 | # Thanks to Jamie Murphy for this code: https://gist.github.com/jacobian/795571
211 | result = {}
212 | for element in xml_etree.iterchildren():
213 | # Remove namespace prefix
214 | key = element.tag.split('}')[1] if '}' in element.tag else element.tag
215 | # Process element as tree element if the inner XML contains non-whitespace content
216 | if element.text and element.text.strip():
217 | value = element.text
218 | else:
219 | value = self.convert_response_dict(element)
220 | if key in result:
221 | if type(result[key]) is list:
222 | result[key].append(value)
223 | else:
224 | tempvalue = result[key].copy()
225 | result[key] = [tempvalue, value]
226 | else:
227 | result[key] = value
228 | return result
229 |
230 | @keyword("Call SOAP Method")
231 | def call_soap_method(self, name, *args, status=None):
232 | """
233 | If the webservice have simple SOAP operation/method with few arguments, you can call the method with the given
234 | `name` and `args`.
235 |
236 | The first argument of the keyword ``name`` is the operation name of the ``SOAP operation/method``
237 | [https://www.soapui.org/soap-and-wsdl/operations-and-requests.html|More information here]
238 |
239 | By default, this keyword fails if a status code different from 200 is returned as response,
240 | this behavior can be modified using the argument status=anything.
241 |
242 | *Input Arguments:*
243 | | *Name* | *Description* |
244 | | name | Name of the SOAP operation/method |
245 | | args | List of request entries |
246 | | status | if set as anything, return the error as a string |
247 |
248 | Note, this keyword uses the most basic method of sending a request, through zeep that creates the xml based
249 | on the wsdl definition. So this keyword does not store the response object, and therefore it is not possible
250 | to use the keyword `Get Last Response Object` after this one.
251 |
252 | *Example:*
253 | | ${response}= | Call SOAP Method | operation_name | arg1 | arg2 |
254 | | ${response}= | Call SOAP Method | operation_name | arg1 | arg2 | status=anything |
255 | """
256 | method = getattr(self.client.service, name)
257 | if status is None:
258 | response = method(*args)
259 | else:
260 | try:
261 | response = method(*args)
262 | except Exception as e:
263 | response = str(e)
264 | return response
265 |
266 | @keyword("Decode Base64")
267 | def decode_base64(self, response):
268 | """
269 | Decodes texts that are base64 encoded.
270 |
271 | Returns the decoded response.
272 |
273 | *Input Arguments:*
274 | | *Name* | *Description* |
275 | | response | Response of the webservice coded in base64 |
276 |
277 | *Example:*
278 | | ${response}= | Call SOAP Method With XML | ${CURDIR}${/}Request.xml |
279 | | ${response_decoded}= | Decode Base64 | ${response} |
280 | """
281 | response_decode = base64.b64decode(response)
282 | return response_decode.decode('utf-8', 'ignore')
283 |
284 | @keyword("Call SOAP Method With String XML")
285 | def call_soap_method_string_xml(self, string_xml, headers=DEFAULT_HEADERS, status=None):
286 | """
287 | Send a string representation of XML as a request to the SOAP client.
288 | The SOAP method is inside the XML string.
289 |
290 | By default, this keyword fails if a status code different from 200 is returned as response,
291 | this behavior can be modified using the argument status=anything.
292 |
293 | *Input Arguments:*
294 | | *Name* | *Description* |
295 | | string_xml | string representation of XML |
296 | | headers | dictionary with request headers. Default ``{'Content-Type': 'text/xml; charset=utf-8'}`` |
297 | | status | optional string: anything |
298 |
299 | *Example:*
300 | | ${response}= | Call SOAP Method With String XML | "1" |
301 | | ${response}= | Call SOAP Method With String XML | "error" | status=anything |
302 | """
303 | xml_obj = etree.fromstring(string_xml)
304 | response = self.client.transport.post_xml(address=self.url, envelope=xml_obj, headers=headers)
305 | self._save_response_object(response)
306 | etree_response = self._parse_from_unicode(response.text)
307 | self._check_and_print_response(response, etree_response, status)
308 | return etree_response
309 |
310 | @keyword("Get Last Response Object")
311 | def get_last_response_object(self):
312 | """
313 | Gets the response object from the last request made. With the object in a variable, you can use the
314 | dot operator to get all the attributes of the response.
315 |
316 | Response object attributes:
317 | | apparent_encoding |
318 | | close |
319 | | connection |
320 | | content |
321 | | cookies |
322 | | elapsed |
323 | | encoding |
324 | | headers |
325 | | history |
326 | | is_permanent_redirect |
327 | | is_redirect |
328 | | iter_content |
329 | | iter_lines |
330 | | json |
331 | | links |
332 | | next |
333 | | ok |
334 | | raise_for_status |
335 | | raw |
336 | | reason |
337 | | request |
338 | | status_code |
339 | | text |
340 | | url |
341 |
342 | Note, this keyword only works after the execution of `Call SOAP Method With XML` or
343 | `Call SOAP Method With String XML`.
344 |
345 | *Example:*
346 | | ${response}= | Call SOAP Method With XML | ${CURDIR}${/}Request.xml |
347 | | ${response_object}= | Get Last Response Object |
348 | | ${response_header}= | Set Variable | ${response_object.headers} |
349 | | ${response_status}= | Set Variable | ${response_object.status_code} |
350 | """
351 | return self.response_obj
352 |
353 | @staticmethod
354 | def _convert_xml_to_raw_text(xml_file_path):
355 | """
356 | Converts a xml file into a string.
357 |
358 | :param xml_file_path: xml file path.
359 | :return: string with xml content.
360 | """
361 | file_content = open(xml_file_path, 'r')
362 | xml = ''
363 | for line in file_content:
364 | xml += line
365 | file_content.close()
366 | return xml
367 |
368 | @staticmethod
369 | def _parse_from_unicode(unicode_str):
370 | """
371 | Parses a unicode string.
372 |
373 | :param unicode_str: unicode string.
374 | :return: parsed string.
375 | """
376 | utf8_parser = etree.XMLParser(encoding='utf-8')
377 | string_utf8 = unicode_str.encode('utf-8')
378 | return etree.fromstring(string_utf8, parser=utf8_parser)
379 |
380 | def _parse_xpath(self, tags):
381 | """
382 | Parses a single xpath or a list of xml tags.
383 |
384 | :param tags: string for a single xml tag or list for multiple xml tags.
385 | :return: parsed xpath.
386 | """
387 | xpath = ''
388 | if isinstance(tags, list):
389 | for el in tags:
390 | xpath += self._replace_xpath_by_local_name(el)
391 | else:
392 | xpath += self._replace_xpath_by_local_name(tags)
393 | return xpath
394 |
395 | def _check_and_print_response(self, response, etree_response, status):
396 | """
397 | Check if the response is 200 when the status is None and pretty print in the robot log.
398 |
399 | :param response: response object.
400 | :param etree_response: response object in etree format.
401 | :param status: if is not None, then don´t raise error.
402 | """
403 | logger.debug('URL: %s' % response.url)
404 | logger.debug(etree.tostring(etree_response, pretty_print=True, encoding='unicode'))
405 | if status is None and response.status_code != 200:
406 | raise AssertionError('Request Error! Status Code: %s! Reason: %s' % (response.status_code, response.reason))
407 | self._print_request_info(etree_response)
408 |
409 | def _save_response_object(self, response):
410 | """
411 | Log the response status code in Robot Framework log and save the response object
412 | for use in the keyword 'Get Last Response Object'
413 |
414 | :param response, zeep response object.
415 | """
416 | logger.info('Status code: %s' % response.status_code)
417 | self.response_obj = response
418 |
419 | @staticmethod
420 | def _convert_string_to_xml(xml_string):
421 | """
422 | Converts a given string to xml object using etree.
423 |
424 | :param xml_string: string with xml content.
425 | :return: xml object.
426 | """
427 | return etree.fromstring(xml_string)
428 |
429 | @staticmethod
430 | def _replace_xpath_by_local_name(xpath_tag):
431 | """
432 | Replaces the given xpath_tag in a xpath using name() function.
433 | Returns the replaced xpath.
434 |
435 | :param xpath_tag: tag to replace with in xpath.
436 | :return: replaced xpath tag.
437 | """
438 | local_name_xpath = "//*[name()='%s']"
439 | return local_name_xpath % xpath_tag
440 |
441 | @staticmethod
442 | def _save_to_file(save_folder, file_name, text):
443 | """
444 | Saves text into a new file.
445 |
446 | :param save_folder: folder to save the new xml file.
447 | :param file_name: name of the new file.
448 | :param text: file text.
449 | :return new file path.
450 | """
451 | new_file_name = "%s.xml" % file_name
452 | new_file_path = os.path.join(save_folder, new_file_name)
453 | request_file = open(new_file_path, 'wb')
454 | request_file.write(text)
455 | request_file.close()
456 | return new_file_path
457 |
458 | @staticmethod
459 | def _print_request_info(etree_response):
460 | """
461 | Pretty print for robot framework log.
462 | """
463 | log_header_response_from_ws = 'Response from webservice: '
464 | logger.info(log_header_response_from_ws, html=True)
465 | logger.info(etree.tostring(etree_response, pretty_print=True, encoding='unicode'))
466 |
--------------------------------------------------------------------------------
/SoapLibrary/__init__.py:
--------------------------------------------------------------------------------
1 | from .SoapLibrary import SoapLibrary
2 |
3 |
4 | class SoapLibrary(SoapLibrary):
5 | """
6 | SoapLibrary is a library for testing SOAP-based web services.
7 |
8 | SoapLibrary is based on [https://python-zeep.readthedocs.io/en/master/|Zeep], a modern SOAP client for Python.
9 |
10 | This library is designed for those who want to work with webservice automation as if they were using SoapUI,
11 | make a request through an XML file, and receive the response in another XML file.
12 |
13 | = Example =
14 |
15 | | ***** Settings *****
16 | | Library SoapLibrary
17 | | Library OperatingSystem
18 | |
19 | | ***** Test Cases *****
20 | | Simple Example
21 | | Create Soap Client http://endpoint.com/example.asmx?wsdl
22 | | ${response} Call SOAP Method Method_name arg1 arg2
23 | | Log ${response}
24 | |
25 | | Example With XML
26 | | Create Soap Client http://endpoint.com/example.asmx?wsdl
27 | | ${response} Call SOAP Method With XML ${CURDIR}/request.xml
28 | | ${text} Get Data From XML By Tag ${response} tag_name
29 | | Log ${text}
30 | | Save XML To File ${response} ${CURDIR} response_test
31 | """
32 | def __init__(self):
33 | pass
34 |
--------------------------------------------------------------------------------
/SoapLibrary/config.py:
--------------------------------------------------------------------------------
1 | DICT_CONFIG = {
2 | 'version': 1,
3 | 'formatters': {
4 | 'verbose': {
5 | 'format': '%(name)s: %(message)s'
6 | }
7 | },
8 | 'handlers': {
9 | 'console': {
10 | 'level': 'DEBUG',
11 | 'class': 'logging.StreamHandler',
12 | 'formatter': 'verbose',
13 | },
14 | },
15 | 'loggers': {
16 | 'zeep.transports': {
17 | 'level': 'DEBUG',
18 | 'propagate': True,
19 | 'handlers': ['console'],
20 | },
21 | }
22 | }
--------------------------------------------------------------------------------
/SoapLibrary/version.py:
--------------------------------------------------------------------------------
1 | VERSION = '1.3'
2 |
--------------------------------------------------------------------------------
/Tests/Requests/New_Request.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | EmailAddress
4 |
5 | 07-06-2020
6 | AAAAA
7 |
8 |
9 | 0000
10 |
11 |
12 |
13 | PhoneNumber
14 |
15 | 07-06-2020
16 | BBBB
17 |
18 |
19 | 0000
20 |
21 |
22 |
23 | PhoneNumber
24 |
25 | 07-06-2020
26 |
27 |
28 | 0000
29 |
30 |
31 |
--------------------------------------------------------------------------------
/Tests/Requests/New_Request_Calculator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 9
5 | 5
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Tests/Requests/Request_Calculator.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 3
5 | 5
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Tests/Requests/Request_Calculator_500.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 3
5 | a
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Tests/Requests/busca_servicos.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | sigep
6 | n5f9t8
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Tests/Requests/consultaCEP.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 88132010
6 | sigep
7 | n5f9t8
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Tests/Requests/request.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | EmailAddress
4 |
5 | 2019-06-03
6 | AAAAA
7 |
8 |
9 | 0000
10 |
11 |
12 |
13 | PhoneNumber
14 |
15 | 2019-06-03
16 | BBBB
17 |
18 |
19 | 0000
20 |
21 |
22 |
23 | PhoneNumber
24 |
25 | 2019-06-03
26 |
27 |
28 | 0000
29 |
30 |
31 |
--------------------------------------------------------------------------------
/Tests/Requests/request_capital.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PT
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Tests/keyword_tests.robot:
--------------------------------------------------------------------------------
1 | *** Settings ***
2 | Library ../SoapLibrary/
3 | Library Collections
4 | Library OperatingSystem
5 | Library XML use_lxml=True
6 | Library Process
7 |
8 | *** Variables ***
9 | ${requests_dir} ${CURDIR}${/}Requests
10 | ${wsdl_correios} https://apphom.correios.com.br/SigepMasterJPA/AtendeClienteService/AtendeCliente?wsdl
11 | ${wsdl_country_info} http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso?wsdl
12 | ${wsdl_calculator} https://ecs.syr.edu/faculty/fawcett/Handouts/cse775/code/calcWebService/Calc.asmx?wsdl
13 | ${request_string} 53
14 | ${request_string_500} a3
15 |
16 | *** Test Cases ***
17 | Test Call Soap Method
18 | [Tags] calculator
19 | Create Soap Client ${wsdl_calculator} ssl_verify=False
20 | ${response} Call SOAP Method Add 2 1
21 | should be equal as integers 3 ${response}
22 |
23 | Test Call Soap Method Error
24 | [Tags] calculator
25 | Create Soap Client ${wsdl_calculator} ssl_verify=False
26 | ${response} Call SOAP Method Add 2 X status=anything
27 | Should Contain ${response} Input string was not in a correct format.
28 |
29 | Test Read
30 | [Tags] calculator
31 | Create Soap Client ${wsdl_calculator} ssl_verify=False
32 | ${response} Call SOAP Method With XML ${requests_dir}${/}Request_Calculator.xml
33 | ${result} Get Data From XML By Tag ${response} AddResult
34 | should be equal 8 ${result}
35 |
36 | Test Read With Binding Address
37 | [Tags] calculator
38 | Create Soap Client ${wsdl_calculator} ssl_verify=False use_binding_address=True
39 | ${response} Call SOAP Method With XML ${requests_dir}${/}Request_Calculator.xml
40 | ${result} Get Data From XML By Tag ${response} AddResult
41 | should be equal 8 ${result}
42 |
43 | Test Read String Xml
44 | [Tags] calculator
45 | Create Soap Client ${wsdl_calculator} ssl_verify=False
46 | ${response} Call SOAP Method With String XML ${request_string}
47 | ${result} Get Data From XML By Tag ${response} AddResult
48 | should be equal 8 ${result}
49 |
50 | Test Edit And Read
51 | [Tags] calculator
52 | Remove File ${requests_dir}${/}New_Request_Calculator.xml
53 | Create Soap Client ${wsdl_calculator} ssl_verify=False
54 | ${dict} Create Dictionary a=9 b=5
55 | ${xml_edited} Edit XML Request ${requests_dir}${/}Request_Calculator.xml ${dict} New_Request_Calculator
56 | ${response} Call SOAP Method With XML ${xml_edited}
57 | ${result} Get Data From XML By Tag ${response} AddResult
58 | should be equal 14 ${result}
59 | Should Exist ${requests_dir}${/}New_Request_Calculator.xml
60 |
61 | Test Call Soap Method With XML Anything
62 | [Tags] calculator
63 | Create Soap Client ${wsdl_calculator} ssl_verify=False
64 | ${response} Call SOAP Method With XML ${requests_dir}${/}Request_Calculator_500.xml status=anything
65 | ${result} Get Data From XML By Tag ${response} faultstring
66 | log ${result}
67 | Should Contain ${result} Server was unable to read request.
68 |
69 | Test Call SOAP Method With String XML Anything
70 | [Tags] calculator
71 | Create Soap Client ${wsdl_calculator} ssl_verify=False
72 | ${response} Call SOAP Method With String XML ${request_string_500} status=anything
73 | ${result} Get Data From XML By Tag ${response} faultstring
74 | log ${result}
75 | Should Contain ${result} Server was unable to read request.
76 |
77 | Test Read UTF8
78 | [Tags] country_info
79 | #todo find an API with response in utf8
80 | Create Soap Client ${wsdl_country_info}
81 | ${response} Call SOAP Method With XML ${requests_dir}${/}request_capital.xml
82 | ${City} Get Data From XML By Tag ${response} m:CapitalCityResult
83 | should be equal as strings ${City} Lisbon
84 |
85 | Test Get Last Response Object
86 | [Tags] country_info
87 | Create Soap Client ${wsdl_country_info}
88 | Call SOAP Method With XML ${requests_dir}${/}request_capital.xml
89 | ${response_object} Get Last Response Object
90 | Should Be Equal As Integers ${response_object.status_code} 200
91 | Should Contain ${response_object.text} Lisbon
92 | Dictionary Should Contain Key ${response_object.headers} Content-Type
93 |
94 | Test Save File Response
95 | [Tags] country_info
96 | Remove File ${CURDIR}${/}response_test.xml
97 | Create Soap Client ${wsdl_country_info}
98 | ${response} Call SOAP Method With XML ${requests_dir}${/}request_capital.xml
99 | ${file} Save XML To File ${response} ${CURDIR} response_test
100 | Should Exist ${CURDIR}${/}response_test.xml
101 |
102 | Test Read Tags With Index
103 | [Tags] correios
104 | Create Soap Client ${wsdl_correios}
105 | ${response} Call SOAP Method With XML ${requests_dir}${/}busca_servicos.xml
106 | ${codigo} Get Data From XML By Tag ${response} codigo index=13
107 | Should Be Equal As Integers ${codigo} 032
108 |
109 | Test Response To Dict
110 | [Tags] correios
111 | Create Soap Client ${wsdl_correios}
112 | ${response} Call SOAP Method With XML ${requests_dir}${/}consultaCEP.xml
113 | ${dict_response} Convert XML Response to Dictionary ${response}
114 | ${type} evaluate str(type(${dict_response}))
115 | Should Contain ${type} 'dict'
116 | ${body} Get From Dictionary ${dict_response} Body
117 | ${city} Set Variable ${dict_response}[Body][consultaCEPResponse][return][cidade]
118 | ${uf} Set Variable ${dict_response}[Body][consultaCEPResponse][return][uf]
119 | Should Be Equal ${city} Palhoça
120 | Should Be Equal ${uf} SC
121 |
122 | Test Edit XML Request 1
123 | [Tags] edit_xml
124 | [Documentation] Change all names, dates and reasons tags
125 | ${new_value_dict} Create Dictionary startDate=15-01-2020 name=Joaquim Reason=1515
126 | ${xml_edited} Edit XML Request ${requests_dir}${/}request.xml ${new_value_dict} New_Request repeated_tags=0
127 | ${new_value_dict} Create Dictionary startDate=16-01-2020 name2=Joao Reason=1616
128 | ${xml_edited} Edit XML Request ${xml_edited} ${new_value_dict} New_Request repeated_tags=1
129 | ${new_value_dict} Create Dictionary startDate=17-01-2020 Reason=1717
130 | ${xml_edited} Edit XML Request ${xml_edited} ${new_value_dict} New_Request repeated_tags=2
131 | ${data} Parse XML ${requests_dir}${/}New_Request.xml keep_clark_notation=True
132 | ${text_name} Evaluate Xpath ${data} //name
133 | Should be equal ${text_name[0].text} Joaquim
134 | ${text_name2} Evaluate Xpath ${data} //name2
135 | Should be equal ${text_name2[0].text} Joao
136 | ${text_date} Evaluate Xpath ${data} //startDate
137 | Should be equal ${text_date[0].text} 15-01-2020
138 | Should be equal ${text_date[1].text} 16-01-2020
139 | Should be equal ${text_date[2].text} 17-01-2020
140 | ${text_reason} Evaluate Xpath ${data} //Reason
141 | Should be equal ${text_reason[0].text} 1515
142 | Should be equal ${text_reason[1].text} 1616
143 | Should be equal ${text_reason[2].text} 1717
144 |
145 | Test Edit XML Request 2
146 | [Tags] edit_xml
147 | [Documentation] Change name, date and reason on tag 0
148 | ${new_value_dict} Create Dictionary startDate=20-01-2020 name=Maria Reason=2020
149 | ${xml_edited} Edit XML Request ${requests_dir}${/}request.xml ${new_value_dict} New_Request repeated_tags=0
150 | ${data} Parse XML ${requests_dir}${/}New_Request.xml keep_clark_notation=True
151 | ${text_name} Evaluate Xpath ${data} //name
152 | Should be equal ${text_name[0].text} Maria
153 | ${text_name2} Evaluate Xpath ${data} //name2
154 | Should be equal ${text_name2[0].text} BBBB
155 | ${text_date} Evaluate Xpath ${data} //startDate
156 | Should be equal ${text_date[0].text} 20-01-2020
157 | Should be equal ${text_date[1].text} 2019-06-03
158 | Should be equal ${text_date[2].text} 2019-06-03
159 | ${text_reason} Evaluate Xpath ${data} //Reason
160 | Should be equal ${text_reason[0].text} 2020
161 | Should be equal ${text_reason[1].text} 0000
162 | Should be equal ${text_reason[2].text} 0000
163 |
164 | Test Edit XML Request 3
165 | [Tags] edit_xml
166 | [Documentation] Change name2, date and reason on tag 1
167 | ${new_value_dict} Create Dictionary startDate=22-01-2020 name2=Joana Reason=2222
168 | ${xml_edited} Edit XML Request ${requests_dir}${/}request.xml ${new_value_dict} New_Request repeated_tags=1
169 | ${data} Parse XML ${requests_dir}${/}New_Request.xml keep_clark_notation=True
170 | ${text_name} Evaluate Xpath ${data} //name
171 | Should be equal ${text_name[0].text} AAAAA
172 | ${text_name2} Evaluate Xpath ${data} //name2
173 | Should be equal ${text_name2[0].text} Joana
174 | ${text_date} Evaluate Xpath ${data} //startDate
175 | Should be equal ${text_date[0].text} 2019-06-03
176 | Should be equal ${text_date[1].text} 22-01-2020
177 | Should be equal ${text_date[2].text} 2019-06-03
178 | ${text_reason} Evaluate Xpath ${data} //Reason
179 | Should be equal ${text_reason[0].text} 0000
180 | Should be equal ${text_reason[1].text} 2222
181 | Should be equal ${text_reason[2].text} 0000
182 |
183 | Test Edit XML Request 4
184 | [Tags] edit_xml
185 | [Documentation] Change date and Reason on tag 2
186 | ${new_value_dict} Create Dictionary startDate=25-01-2020 Reason=2525
187 | ${xml_edited} Edit XML Request ${requests_dir}${/}request.xml ${new_value_dict} New_Request repeated_tags=2
188 | ${data} Parse XML ${requests_dir}${/}New_Request.xml keep_clark_notation=True
189 | ${text_name} Evaluate Xpath ${data} //name
190 | Should be equal ${text_name[0].text} AAAAA
191 | ${text_name2} Evaluate Xpath ${data} //name2
192 | Should be equal ${text_name2[0].text} BBBB
193 | ${text_date} Evaluate Xpath ${data} //startDate
194 | Should be equal ${text_date[0].text} 2019-06-03
195 | Should be equal ${text_date[1].text} 2019-06-03
196 | Should be equal ${text_date[2].text} 25-01-2020
197 | ${text_reason} Evaluate Xpath ${data} //Reason
198 | Should be equal ${text_reason[0].text} 0000
199 | Should be equal ${text_reason[1].text} 0000
200 | Should be equal ${text_reason[2].text} 2525
201 |
202 | Test Edit XML Request 5
203 | [Tags] edit_xml
204 | [Documentation] Change name, date and reason in Tags 0 and 1
205 | ${new_value_dict} Create Dictionary startDate=15-01-2020 name=Joaquim Reason=1515
206 | ${xml_edited} Edit XML Request ${requests_dir}${/}request.xml ${new_value_dict} New_Request repeated_tags=0
207 | ${new_value_dict} Create Dictionary startDate=16-01-2020 name2=Joao Reason=1616
208 | ${xml_edited} Edit XML Request ${xml_edited} ${new_value_dict} New_Request repeated_tags=1
209 | ${data} Parse XML ${requests_dir}${/}New_Request.xml keep_clark_notation=True
210 | ${text_name} Evaluate Xpath ${data} //name
211 | Should be equal ${text_name[0].text} Joaquim
212 | ${text_name2} Evaluate Xpath ${data} //name2
213 | Should be equal ${text_name2[0].text} Joao
214 | ${text_date} Evaluate Xpath ${data} //startDate
215 | Should be equal ${text_date[0].text} 15-01-2020
216 | Should be equal ${text_date[1].text} 16-01-2020
217 | Should be equal ${text_date[2].text} 2019-06-03
218 | ${text_reason} Evaluate Xpath ${data} //Reason
219 | Should be equal ${text_reason[0].text} 1515
220 | Should be equal ${text_reason[1].text} 1616
221 | Should be equal ${text_reason[2].text} 0000
222 |
223 | Test Edit XML Request 6
224 | [Tags] edit_xml
225 | [Documentation] Change name, date and reason in Tags 1 and 2
226 | ${new_value_dict} Create Dictionary startDate=15-01-2020 name2=Joaquim Reason=1515
227 | ${xml_edited} Edit XML Request ${requests_dir}${/}request.xml ${new_value_dict} New_Request repeated_tags=1
228 | ${new_value_dict} Create Dictionary startDate=16-01-2020 Reason=1616
229 | ${xml_edited} Edit XML Request ${xml_edited} ${new_value_dict} New_Request repeated_tags=2
230 | ${data} Parse XML ${requests_dir}${/}New_Request.xml keep_clark_notation=True
231 | ${text_name} Evaluate Xpath ${data} //name
232 | Should be equal ${text_name[0].text} AAAAA
233 | ${text_name2} Evaluate Xpath ${data} //name2
234 | Should be equal ${text_name2[0].text} Joaquim
235 | ${text_date} Evaluate Xpath ${data} //startDate
236 | Should be equal ${text_date[0].text} 2019-06-03
237 | Should be equal ${text_date[1].text} 15-01-2020
238 | Should be equal ${text_date[2].text} 16-01-2020
239 | ${text_reason} Evaluate Xpath ${data} //Reason
240 | Should be equal ${text_reason[0].text} 0000
241 | Should be equal ${text_reason[1].text} 1515
242 | Should be equal ${text_reason[2].text} 1616
243 |
244 | Test Edit XML Request 7
245 | [Tags] edit_xml
246 | [Documentation] Change only the name tag
247 | ${new_value_dict} Create Dictionary name=Carlota
248 | ${xml_edited} Edit XML Request ${requests_dir}${/}request.xml ${new_value_dict} New_Request
249 | ${data} Parse XML ${requests_dir}${/}New_Request.xml keep_clark_notation=True
250 | ${text_name} Evaluate Xpath ${data} //name
251 | Should be equal ${text_name[0].text} Carlota
252 | ${text_name2} Evaluate Xpath ${data} //name2
253 | Should be equal ${text_name2[0].text} BBBB
254 | ${text_date} Evaluate Xpath ${data} //startDate
255 | Should be equal ${text_date[0].text} 2019-06-03
256 | Should be equal ${text_date[1].text} 2019-06-03
257 | Should be equal ${text_date[2].text} 2019-06-03
258 | ${text_reason} Evaluate Xpath ${data} //Reason
259 | Should be equal ${text_reason[0].text} 0000
260 | Should be equal ${text_reason[1].text} 0000
261 | Should be equal ${text_reason[2].text} 0000
262 |
263 | Test Edit XML Request 8
264 | [Tags] edit_xml
265 | [Documentation] Change all dates tags
266 | ${new_value_dict} Create Dictionary startDate=07-06-2020
267 | ${xml_edited} Edit XML Request ${requests_dir}${/}request.xml ${new_value_dict} New_Request
268 | ${data} Parse XML ${requests_dir}${/}New_Request.xml keep_clark_notation=True
269 | ${text_name} Evaluate Xpath ${data} //name
270 | Should be equal ${text_name[0].text} AAAAA
271 | ${text_name2} Evaluate Xpath ${data} //name2
272 | Should be equal ${text_name2[0].text} BBBB
273 | ${text_date} Evaluate Xpath ${data} //startDate
274 | Should be equal ${text_date[0].text} 07-06-2020
275 | Should be equal ${text_date[1].text} 07-06-2020
276 | Should be equal ${text_date[2].text} 07-06-2020
277 | ${text_reason} Evaluate Xpath ${data} //Reason
278 | Should be equal ${text_reason[0].text} 0000
279 | Should be equal ${text_reason[1].text} 0000
280 | Should be equal ${text_reason[2].text} 0000
281 |
--------------------------------------------------------------------------------
/dist/robotframework-soaplibrary-0.8.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarketSquare/Robot-Framework-SOAP-Library/4c0a37b4b1f789765dae3808f81ab40535f1c0d6/dist/robotframework-soaplibrary-0.8.tar.gz
--------------------------------------------------------------------------------
/dist/robotframework-soaplibrary-0.9.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarketSquare/Robot-Framework-SOAP-Library/4c0a37b4b1f789765dae3808f81ab40535f1c0d6/dist/robotframework-soaplibrary-0.9.tar.gz
--------------------------------------------------------------------------------
/dist/robotframework-soaplibrary-1.0.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarketSquare/Robot-Framework-SOAP-Library/4c0a37b4b1f789765dae3808f81ab40535f1c0d6/dist/robotframework-soaplibrary-1.0.tar.gz
--------------------------------------------------------------------------------
/dist/robotframework-soaplibrary-1.2.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarketSquare/Robot-Framework-SOAP-Library/4c0a37b4b1f789765dae3808f81ab40535f1c0d6/dist/robotframework-soaplibrary-1.2.tar.gz
--------------------------------------------------------------------------------
/dist/robotframework-soaplibrary-1.3.tar.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MarketSquare/Robot-Framework-SOAP-Library/4c0a37b4b1f789765dae3808f81ab40535f1c0d6/dist/robotframework-soaplibrary-1.3.tar.gz
--------------------------------------------------------------------------------
/examples/request/cep.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 01305901
6 |
7 |
8 |
--------------------------------------------------------------------------------
/examples/request/ip.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 8.8.8.8
7 | 0
8 |
9 |
10 |
--------------------------------------------------------------------------------
/examples/samples.robot:
--------------------------------------------------------------------------------
1 | *** Settings ***
2 | Library SoapLibrary
3 | Library Collections
4 |
5 | *** Variables ***
6 | ${wsdl_brazilian_post_office} https://apps.correios.com.br/SigepMasterJPA/AtendeClienteService/AtendeCliente?wsdl
7 | ${wsdl_ip_geo} http://ws.cdyne.com/ip2geo/ip2geo.asmx?wsdl
8 |
9 | *** Test Cases ***
10 | Test with Convert XML Response to Dictionary
11 | [Documentation] Test with 'Call SOAP Method With XML' and get the response values using ´Convert XML Response to Dictionary´
12 | Create SOAP Client ${wsdl_ip_geo}
13 | ${response} Call SOAP Method With XML ${CURDIR}/request/ip.xml
14 | ${dict_response} Convert XML Response to Dictionary ${response}
15 | ${body} Get From Dictionary ${dict_response} Body
16 | ${resolveipresponse} Get From Dictionary ${body} ResolveIPResponse
17 | ${resolveipresult} Get From Dictionary ${ResolveIPResponse} ResolveIPResult
18 | ${country} Get From Dictionary ${ResolveIPResult} Country
19 | ${latitude} Get From Dictionary ${ResolveIPResult} Latitude
20 | ${longitude} Get From Dictionary ${ResolveIPResult} Longitude
21 | ${areacode} Get From Dictionary ${ResolveIPResult} AreaCode
22 | ${certainty} Get From Dictionary ${ResolveIPResult} Certainty
23 | ${countrycode} Get From Dictionary ${ResolveIPResult} CountryCode
24 | Log ${country}
25 | Log ${latitude}
26 | Log ${longitude}
27 | Log ${areacode}
28 | Log ${certainty}
29 | Log ${countrycode}
30 |
31 | Test with Get Data From XML By Tag
32 | [Documentation] Test with 'Call SOAP Method With XML' and get the response values using ´Get Data From XML By Tag´
33 | Create SOAP Client ${wsdl_brazilian_post_office}
34 | ${response} Call SOAP Method With XML ${CURDIR}/request/cep.xml
35 | ${postal_code} Get Data From XML By Tag ${response} cep
36 | ${city} Get Data From XML By Tag ${response} cidade
37 | ${street} Get Data From XML By Tag ${response} end
38 | ${state} Get Data From XML By Tag ${response} uf
39 | Log ${postal_code}
40 | Log ${city}
41 | Log ${street}
42 | Log ${state}
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | requests>=2.31.0
2 | robotframework>=5.0.1
3 | urllib3>=1.26.18
4 | zeep>=4.2.1
5 | lxml>=4.9.1
--------------------------------------------------------------------------------
/robotframework_soaplibrary.egg-info/PKG-INFO:
--------------------------------------------------------------------------------
1 | Metadata-Version: 2.1
2 | Name: robotframework-soaplibrary
3 | Version: 1.3
4 | Summary: SOAP Library for Robot Framework
5 | Home-page: https://github.com/Altran-PT-GDC/Robot-Framework-SOAP-Library
6 | Author: Altran Portugal
7 | Author-email: samuca@gmail.com
8 | License: MIT License
9 | Platform: UNKNOWN
10 | License-File: LICENSE.md
11 |
12 | Test library for Robot Framework to create automated test like using SOAPUI
13 |
14 |
--------------------------------------------------------------------------------
/robotframework_soaplibrary.egg-info/SOURCES.txt:
--------------------------------------------------------------------------------
1 | LICENSE.md
2 | README.md
3 | setup.py
4 | SoapLibrary/SoapLibrary.py
5 | SoapLibrary/__init__.py
6 | SoapLibrary/config.py
7 | SoapLibrary/version.py
8 | robotframework_soaplibrary.egg-info/PKG-INFO
9 | robotframework_soaplibrary.egg-info/SOURCES.txt
10 | robotframework_soaplibrary.egg-info/dependency_links.txt
11 | robotframework_soaplibrary.egg-info/requires.txt
12 | robotframework_soaplibrary.egg-info/top_level.txt
--------------------------------------------------------------------------------
/robotframework_soaplibrary.egg-info/dependency_links.txt:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/robotframework_soaplibrary.egg-info/requires.txt:
--------------------------------------------------------------------------------
1 | robotframework
2 | zeep
3 | requests
4 | urllib3
5 |
--------------------------------------------------------------------------------
/robotframework_soaplibrary.egg-info/top_level.txt:
--------------------------------------------------------------------------------
1 | SoapLibrary
2 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from os.path import abspath, dirname, join
3 |
4 | try:
5 | from setuptools import setup
6 | except ImportError as error:
7 | from distutils.core import setup
8 |
9 |
10 | version_file = join(dirname(abspath(__file__)), 'SoapLibrary', 'version.py')
11 |
12 | with open(version_file) as file:
13 | code = compile(file.read(), version_file, 'exec')
14 | exec(code)
15 |
16 | setup(name = 'robotframework-soaplibrary',
17 | version = '1.3',
18 | description = 'SOAP Library for Robot Framework',
19 | long_description = 'Test library for Robot Framework to create automated test like using SOAPUI',
20 | author = 'Altran Portugal',
21 | author_email = 'samuca@gmail.com',
22 | license = 'MIT License',
23 | url = 'https://github.com/Altran-PT-GDC/Robot-Framework-SOAP-Library',
24 | packages = ['SoapLibrary'],
25 | install_requires = ['robotframework', 'zeep', 'requests', 'urllib3']
26 | )
27 |
--------------------------------------------------------------------------------