Skip to content

Instantly share code, notes, and snippets.

@dmizverev
Last active November 4, 2019 09:43
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save dmizverev/8c3e37787f6442679837 to your computer and use it in GitHub Desktop.
Save dmizverev/8c3e37787f6442679837 to your computer and use it in GitHub Desktop.
Robot Framework REST API
*** Settings ***
Documentation Примеры тестов для тестирования REST API.
...
... == Зависимости ==
... - [ https://github.com/dmizverev/robot-framework-library/blob/master/library/JsonValidator.py | JsonValidator ]
... - [ https://github.com/dmizverev/robot-framework-library/blob/master/library/OracleDB.py | OracleDb]
... - [ https://github.com/bulkan/robotframework-requests | RequestsLibrary]
... - [ http://robotframework.org/robotframework/latest/libraries/Collections.html | Collections]
Resource ..${/}resource${/}common.txt
Suite Setup Suite_Setup
Suite Teardown Suite_Teardown
Force Tags demo
# -*- coding: utf-8 -*-
from robot.libraries.BuiltIn import BuiltIn
from robot.api import logger
import json
import base64
from db_operations import db_operations
def _http_lib():
return BuiltIn().get_library_instance("RequestsLibrary")
def _log_responce(responce):
"""
Пример логирования http запроса и ответа
*Args:*\n
_responce_ - объект [ http://docs.python-requests.org/en/latest/api/#requests.Response | "Responce" ]
"""
message="""
<b>REQUEST</b>
Headers: {req_headers}
Body: {req_body}
<b>RESPONCE</b>
Headers: {resp_headers}
Body: {resp_body}
Status code: {code} {reason}""".format(req_headers=responce.request.headers,
req_body=responce.request.body,
resp_headers=responce.headers,
resp_body=responce.content,
code=responce.status_code,
reason=responce.reason)
logger.debug(message, html=True)
class token(object):
"""
Класс для работы с http-запросами токена
"""
def get_token(self, alias, username, password):
"""
Получение авторизационного токена
*Args:*\n
_alias_ - псевдоним RequestsLibrary для идентификации http сессии \n
_username_ - имя пользователя \n
_password_ - пароль польователя \n
*Returns:*\n
Авторизационный токен.
"""
token=base64.b64encode(username+password)
uri='/get?token={0}'.format(token)
responce=_http_lib().get(alias, uri)
body=json.loads(responce.content)
resp_token=body['args']['token']
logger.debug('token={0}'.format(resp_token))
return resp_token
class msisdn(object):
"""
Класс для работы с методами API, отвечающими за MSISDN
"""
def get_msisdn(self, alias, token, params):
"""
Получение MSISDN пользователя
*Args:*\n
_alias_ - псевдоним RequestsLibrary для идентификации http сессии \n
_token_ - токен пользователя \n
_params_ - параметры запроса; описание параметров смотри в ТС-123, п. 3.2.1
*Returns:*\n
Oбъект [ http://docs.python-requests.org/en/latest/api/#requests.Response | "Responce" ]
"""
# декодирование параметров, т.к. они могут быть, например, на русском
parameters=params.encode('utf-8')
# составление uri запроса
uri='/get?{0}&auth_token={1}'.format(parameters, token)
# вызов http-запроса и получение ответа
responce=_http_lib().get(alias, uri)
# логирование запроса и ответа
_log_responce(responce)
# возвращаем ответ "как есть" без сериализации в json или проверки кода ответа
# обо всем этом позаботимся уже в тесте
return responce
class users(object):
"""
Класс для работы с методами API, отвечающими за действия с пользователями
"""
def create_users(self, alias, token, params):
"""
Создание пользователей
*Args:*\n
_alias_ - псевдоним RequestsLibrary для идентификации http сессии \n
_token_ - токен пользователя \n
_params_ - список параметров запроса содания польователя; описание параметров смотри в ТС-123, п. 1.2.3.
*Returns:*\n
Oбъект [ http://docs.python-requests.org/en/latest/api/#requests.Response | "Responce" ]
"""
# составление uri запроса
uri='/post?auth_token={0}'.format(token)
# десериалиуем список в json-строку
data=json.dumps(params)
# вызов http-запроса и получение ответа
responce=_http_lib().post(alias, uri, data)
# логирование запроса и ответа
_log_responce(responce)
# возвращаем ответ "как есть" без сериализации в json или проверки кода ответа
# обо всем этом позаботимся уже в тесте
return responce
class default_params(object):
"""
Класс дефолтных параметров для api методов
"""
def params_create_user(self, username):
"""
Дефолтные параметры для метода "create_user" (создание пользователя)
*Args:*\n
_username_ - имя пользователя
*Returns:*\n
Список с параметрами \n
Пример: \n
| [
| {
| 'msisdn': '9111234567',
| 'region': 'Moscow',
| 'type': 'simple type',
| 'name': 'user1',
| 'id': 1
| }
| ]
"""
# инициалиации списка и словаря, в который будут добавляться параметры
users_list=[]
user_dict={}
# добавление параметров в словарь
user_dict['name']=username
user_dict['msisdn']='9111234567'
# некоторые параметры мы можем получать из БД, например, тип пользователя
user_dict['type']=db_operations().get_type()
user_dict['id']=1
user_dict['region']='Moscow'
# добавляем словарь в список
users_list.append(user_dict.copy())
# возвращаем список
return users_list
class api_methods(token, msisdn, users, default_params):
"""
Методы работы с API
== Зависимости ==
| RequestsLibrary | https://github.com/bulkan/robotframework-requests |
| db_operations.py | |
"""
ROBOT_LIBRARY_SCOPE='GLOBAL'
# -*- coding: utf-8 -*-
from robot.libraries.BuiltIn import BuiltIn
import json
from db_operations import db_operations
from JsonValidator import JsonValidator
class checks(object):
"""
Проверки ответов от сервиса API
== Зависимости ==
- db_operations.py
- [ https://github.com/dmizverev/robot-framework-library/blob/master/library/JsonValidator.py | JsonValidator ]
"""
ROBOT_LIBRARY_SCOPE='GLOBAL'
def check_msisdn (self, api_resp):
"""
Проверка MSISDN
*Args:*\n
_api_resp_ - ответ от сервиса api: объект [ http://docs.python-requests.org/en/latest/api/#requests.Response | "Responce" ] от сервиса
"""
# сериализуем ответ в структуру python (в данном случае словарь)
body=json.loads(api_resp.content)
# имя пользователя из api-ответа
api_user=body['args']['user']
# MSISDN из api-ответа
api_msisdn=body['args']['msisdn']
# получаем MSISDN из базы данных, указывая в качестве параметра имя пользователя из api-ответа
db_msisdn=db_operations().get_msisdn_of_user(api_user)
# проверяем, что MSISDN из БД и из api-ответа совпадают
BuiltIn().should_be_equal_as_strings(api_msisdn, db_msisdn, "MSISDN is not equals")
def check_param1(self, api_resp):
"""
Проверка параметра через jsonpath
*Args:*\n
_api_resp_ - ответ от сервиса api: объект [ http://docs.python-requests.org/en/latest/api/#requests.Response | "Responce" ] от сервиса
"""
value1 = JsonValidator().get_elements(api_resp.content, '$..param1')
BuiltIn().should_be_equal_as_strings(value1[0], 'значение'.decode('utf-8'), "Param1 is not equals")
def check_region(self, api_resp):
"""
Проверка филиала
*Args:*\n
_api_resp_ - ответ от сервиса api: объект [ http://docs.python-requests.org/en/latest/api/#requests.Response | "Responce" ] от сервиса
Пример api_resp: \n
| {
| 'json':
| [
| {
| 'msisdn': '9111234567',
| 'region': 'Moscow',
| 'type': 'simple type',
| 'name': 'user0',
| 'id': 1
| },
| {
| 'msisdn': '9111234567',
| 'region': 'Saint-Petersburg',
| 'type': 'another type',
| 'name': 'user1',
| 'id': 2
| }
| ]
| }
"""
# сериализуем ответ в структуру python (в данном случае список)
body=json.loads(api_resp.content)
# будем выполнять проверку для каждого элемента списка, item - это номер элемента
for item, _ in enumerate(body["json"]):
# имя пользователя из api-ответа
api_user=body["json"][item]["name"]
# филиал из api-ответа
api_region=body["json"][item]["region"]
# получаем филиал из БД, указывая в качестве параметра имя пользователя из api-ответа
db_id=db_operations().get_region_of_user(api_user)
# проверяем, что филиалы из БД и из api-ответа совпадают
BuiltIn().should_be_equal_as_strings(api_region, db_id, "Region is not equals")
*** Settings ***
Library RequestsLibrary # библиотека для работы с http запросами
Library Collections # библиотека для работы со списками и словарями
Library OracleDB # библиотека для работы с БД Oracle
Library ..${/}library${/}api_methods.py WITH NAME ApiMethods
Library ..${/}library${/}db_operations.py WITH NAME DbOperations
Library ..${/}library${/}checks.py WITH NAME Checks
Variables ..${/}variable${/}global.py
*** Keywords ***
Suite_Setup
[Documentation] Предварительные шаги тест-сьютов
Comment Словарь с заголовками, отправляемыми во всех http-запросах
${headers}= Collections.Create dictionary Content-Type=application/json; charset=UTF-8
Comment Создание http-сессии с тестируемом сервисом
RequestsLibrary.Create Session ${ALIAS} ${URL} ${headers}
Comment Получение токена
${resp}= ApiMethods.Get Token ${ALIAS} ${USERNAME} ${PASSWORD}
Set global variable ${ADMIN_TOKEN} ${resp}
Comment Подключение к базе данных
OracleDb.Connect To Oracle ${BIS_DB_NAME} ${BIS_DB_LOGIN} ${BIS_DB_PASSWORD}
Suite_Teardown
[Documentation] Завершающие шаги тест-сьютов
Comment Отключение от http-сервиса и базы данных
RequestsLibrary.Delete All Sessions
OracleDb.Disconnect from oracle
# -*- coding: utf-8 -*-
from robot.libraries.BuiltIn import BuiltIn
from robot.api import logger
def _oracle_lib():
return BuiltIn().get_library_instance("OracleDB")
class db_operations(object):
"""
Библиотека кейвордов для запросав в базу данных.
== Зависимости ==
| OracleDB | http://git.billing.ru/cgit/PS_RF.git/tree/User_Part/Source/library/OracleDB.py |
"""
ROBOT_LIBRARY_SCOPE='GLOBAL'
def get_msisdn_of_user (self, user):
"""
Получение MSISDN пользователя
*Args:*\n
_user_ - имя пользователя
*Returns:*\n
MSISDN пользователя в виде строки
"""
# подготавливаем sql-строку
sql="""select '9111234567' as msisdn, '{0}' as username
from dual""".format(user)
# выполняем sql-запрос
db_resp=_oracle_lib().execute_sql_string(sql)
# логируем ответ
logger.debug (db_resp)
# возвращаем первую ячейку таблицы
return db_resp[0][0].decode('windows-1251')
def get_type(self):
"""
Получение типа пользователя
"""
# подготавливаем sql-строку
sql="select 'администратор' as type from dual"
# выполняем sql-запрос
db_resp=_oracle_lib().execute_sql_string(sql)
# логируем ответ
logger.debug (db_resp)
# возвращаем первую ячейку таблицы
return db_resp[0][0].decode('windows-1251')
def get_region_of_user(self, user):
"""
Получение филиала пользователя
*Args:*\n
_user_ - имя пользователя
"""
sql="""select 'Moscow' as region, '{0}' as username
from dual""".format(user)
db_resp=_oracle_lib().execute_sql_string(sql)
logger.debug (db_resp)
return db_resp[0][0].decode('windows-1251')
** Settings ***
Documentation Примеры GET-запросов.
Resource ..${/}resource${/}common.txt
Test Timeout 1 minute
*** Test Cases ***
Get_MSISDN
[Documentation] Пример GET-запроса и работы с json-ответом
Comment Отправка API запроса. В логе можно видеть, что все параметры корректно перекодировались.
${resp}= ApiMethods.Get MSISDN ${ALIAS} ${ADMIN_TOKEN} msisdn=9111234567&user=name1&param1=значение&param2=va lue2
Comment Проверка кода ответа
Should be equal as strings ${resp.status_code} 200
Comment Функциональная проверка
Checks.Check MSISDN ${resp}
Checks.Check Param1 ${resp}
Comment Пример работы с json-ответом
${json_body}= RequestsLibrary.To json ${resp.content}
Log ${json_body["args"]["param1"]}
Comment Пример работы с объектом ответа на API запрос. Получение заголовка запроса.
Log ${resp.request.headers["User-Agent"]}
Check different combination of parameters
[Documentation] Пример data driven теста с переменным числом и значением параметров
[Template] Get MSISDN and check
msisdn=9111234567&user=name1
msisdn=9111234567&user=name1&param1=value1
msisdn=9111234567&user=name1&param5=value№5&param2=value2
*** Keywords ***
Get MSISDN and check
[Documentation] Получение MSISDN и проверка ответа по базе данных
...
... *Args:*\n\n
... _params_ - параметры запроса получения MSISDN.
[Arguments] ${params}
${resp}= ApiMethods.Get MSISDN alias=${ALIAS} token=${ADMIN_TOKEN} params=${params}
Should be equal as strings ${resp.status_code} 200
Checks.Check MSISDN ${resp}
# -*- coding: utf-8 -*-
HOST = 'httpbin.org' # api-хост
PORT = '80' # api-порт
URL = 'http://{host}:{port}'.format(host=HOST, port=PORT) # вызываемый url api
ALIAS= 'api_service' # псевдоним, используемый для вызова этого url
USERNAME= 'Admin' # логин пользователя api
PASSWORD= 'pwd' # пароль польователя api
BIS_DB_NAME = 'bpublic.net.billing.ru' # схема БД
BIS_DB_LOGIN = 'bis' # логин пользователя БД
BIS_DB_PASSWORD = 'employer123' # пароль пользователя БД
*** Settings ***
Documentation Примеры POST-запросов.
Resource ..${/}resource${/}common.txt
Test Timeout 2 minutes
*** Test Cases ***
Create user
[Documentation] Пример POST-запроса и работы с json-ответом
Comment Получение дефолтных параметров
${params}= ApiMethods.Params create_user user1
Comment Меняем один из дефолтных параметров: type=admin
Set To Dictionary ${params[0]} type admin type
Comment Отправка API запроса
${resp}= ApiMethods.Create users ${ALIAS} ${ADMIN_TOKEN} ${params}
Comment Проверка кода ответа
Should be equal as strings ${resp.status_code} 200
Comment Функциональная проверка
Checks.Check region ${resp}
Comment Пример работы с json-ответом
${json_body}= RequestsLibrary.To json ${resp.content}
Log ${json_body["json"][0]["type"]}
Comment Пример работы с объектом ответа на API запрос. Получение тела запроса.
Log ${resp.request.body}
Check different user types in several users
[Documentation] Пример data driven теста различным значением параметра type
...
... Создание разного количества пользователей с разным типом
[Template] Create several users and check region
#number of users type
1 test type
2 customer type
4 admin type
*** Keywords ***
Create several users and check region
[Documentation] Создание разного количества пользователей с разным типом
...
... *Args:*\n\n
... _number_ - количество создаваемых пользователей\n\n
... _type_ - тип создаваемых пользователей
[Arguments] ${number} ${type}
# Создадим список в который будем записывать параметры пользователей. Его размер будет равен number
${params}= Create list
:FOR ${index} IN RANGE ${number}
# Получаем дефолтные параметры для создания пользователя
\ ${default_params}= ApiMethods.Params create_user user${index}
# Меняем в дефолтных параметрах тип пользователя
\ Set To Dictionary ${default_params[0]} type ${type}
# Добавляем в список весь словарь с параметрами
\ Collections.Append To List ${params} ${default_params[0]}
# отправка API запроса
${resp}= ApiMethods.Create users ${ALIAS} ${ADMIN_TOKEN} ${params}
# функциональная проверка
Checks.Check region ${resp}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment