StRESTester is a Python tool for testing RESTful APIs compilant with Swagger 1.2 or Swagger 2.0 specification.
- validators
- aiohttp
- invoke
- jinja2
- create your config.json (there is sample_config.json)
- create your scenario.xml (there is sample_scenario.xml)
- python3 -m pip install requirements.txt
- invoke run -c config.json -s scenario.xml
sample_config.json
{
"urls": {
"api_url_1": "http://127.0.0.1:8000",
"api_url_2": "http://127.0.0.1:8080"
},
"users_number": 10,
"iterations_number": 3,
"workers_number": 6
}
- urls - list of api urls
- users_number - number of test users making requests asyncroniously
- workers_number - number of parallel processes of testing
- iterations_number - number of stress test scenario iterations
sample_scenario.xml
<scenario>
<rest name="Create User">
<method>POST</method>
<url>{{ api_url_1 }}/accounts/</url>
<data>{"login": "{{ username }}", "password": "{{ password }}"}</data>
</rest>
<rest name="Get Auth Token" return="token_1">
<method>POST</method>
<url>{{ api_url_1 }}/tokens/</url>
<data>{"login": "{{ username }}", "password": "{{ password }}"}</data>
</rest>
<rest name="Login" return="token_2_info">
<method>POST</method>
<url>{{ api_url_2 }}/accounts/login/</url>
<data>{{ token_1 }}</data>
<raw>True</raw>
<headers>{"content-type": "application/json"}</headers>
</rest>
<get name="get token_2" return="token_2">
<info>{{ token_2_info }}</info>
<key>token</key>
</get>
<rest name="Create Profile" return="user_info">
<method>POST</method>
<url>{{ api_url_2 }}/accounts/profile/</url>
<data>{"nickname": "{{ username }}"}</data>
<headers>{"content-type": "application/json", "Token": "{{ token_2 }}"}</headers>
<raw>True</raw>
</rest>
<get name="get profile_info" return="profile_info">
<info>{{ user_info }}</info>
<key>profile</key>
</get>
<get name="get profile_id" return="profile_id">
<info>{{ profile_info }}</info>
<key>profile_id</key>
</get>
<get name="get user_id" return="user_id">
<info>{{ profile_info }}</info>
<key>user_id</key>
</get>
<repeat cycles="5">
<rest name="Set user wallet to 10" ignore_errors="True">
<method>PUT</method>
<url>{{ api }}/super/bank/{{ user_id }}</url>
<data>{"amount": 10}</data>
<headers>{"content-type": "application/json"}</headers>
<raw>True</raw>
</rest>
<rest name="Get user wallet">
<method>GET</method>
<url>{{ api_url_2 }}/accounts/bank/</url>
<headers>{"content-type": "application/json", "Token": "{{ token_2 }}" }</headers>
</rest>
<rest name="Patch money amount">
<method>PATCH</method>
<url>{{ api_url_2 }}/super/bank/{{ user_id }}</url>
<data>{"amount": 10}</data>
<headers>{"content-type": "application/json"}</headers>
<raw>True</raw>
</rest>
</repeat>
<rest name="Delete profile">
<method>DELETE</method>
<url>{{ api_url_2 }}/super/profiles/</url>
<params>{"profile_id": "{{ profile_id }}", "user_id": "{{ user_id }}"}</params>
</rest>
<rest name="Delete User">
<method>DELETE</method>
<url>{{ api_url_1 }}/accounts/{{ username }}</url>
</rest>
</scenario>
- scenario consists of snippets, so called actions ('rest', 'get')
- list of actions can be extended
- each action must have mandatory attribute 'name'
- attribute 'return' intended for assignment return of action to given variable
- attribute 'ignore_errors' allows to ignore failed actions
- node 'repeat' allows to create loops of scenario snippets, meaning of the attribute 'cycles' is obvious
- jinja2 template is used to define action arguments
- report output looks like
Action metrics (averages):
{ 'Create Profile': 0.162066854249167,
'Create User': 0.29612173768576905,
'Delete User': 0.07070714197972627,
'Delete profile': 0.08907260841132114,
'Get Auth Token': 0.2546299340232598,
'Get user wallet': 0.012372952839989002,
'Login': 0.03050658500530956,
'Patch money amount': 0.09161834647939628,
'Set user wallet to 10': 0.11090895620377335}
Error metrics:
{}
values are excecution time of rest actions in seconds
- create python module in src/action_registry
- here is an example of custom action:
import asyncio
from action_registry.registry import register_action_decorator
__all__ = ['async_sleep']
@register_action_decorator(action_name='sleep')
async def async_sleep(sec):
await asyncio.sleep(sec)
- Implement web ui for stress test scenario generation and running and better report output
- Dockerize application
- Fork it ( http://github.com/olexandr-klymenko/StRESTester/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request