Metadata-Version: 2.4
Name: robotframework-schemathesislibrary
Version: 2.3.0
Summary: Robot Framework SchemathesisLibrary to automatically create test cases from API specifications.
Author-email: Tatu Aalto <aalto.tatu@gmail.com>
License-Expression: Apache-2.0
Keywords: Robot Framework,Schemathesis,API Testing,Test Automation
Requires-Python: >=3.10.1
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: robotframework>=7.2.2
Requires-Dist: robotframework-datadriver>=1.11.2
Requires-Dist: robotframework-pythonlibcore>=4.4.1
Requires-Dist: schemathesis>=4.7.0
Dynamic: license-file

# Robot Framework SchemathesisLibrary
Robot Framework SchemathesisLibrary is a library build top of the
[Schemathesis](https://github.com/schemathesis/schemathesis).
Schemathesis automatically generates thousands of test cases from
your OpenAPI or GraphQL schema and finds edge cases that break your
API.

SchemathesisLibrary uses
[DataDriver](https://github.com/Snooz82/robotframework-datadriver)
to create test cases from the Schemathesis
[Case](https://schemathesis.readthedocs.io/en/stable/reference/python/#schemathesis.Case)
object.

# Installation
Install with [pip](https://pypi.org/project/pip/), [uv](https://docs.astral.sh/uv/)
or any package manager that supports PyPi

```bash
pip install robotframework-schemathesislibrary
```

# Keyword documentation
See
[keyword documentation](https://aaltat.github.io/robotframework-schemathesis/SchemathesisLibrary.html)
for more details. A link older keyword documentation can be found from
[versions page](https://aaltat.github.io/robotframework-schemathesis/versions/)

# Usage
Test are automatically generated based your API specification, SchemathesisLibrary uses
DataDriver internally, but you need to create template suite, so that DataDriver is able
to create needed test for your test suite.

SchemathesisLibrary must be imported by `url` or `path` argument, which tell where
the API specification can obtained. As like with Datadriver, there must be
[Test Template](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#test-templates)
setting defined. The template keyword must take one argument, usually referred as
`${case}` and the template keyword must call `Call And Validate` keyword with the
`${case}` argument.

Example test suite:
```robotframework
*** Settings ***
Library             SchemathesisLibrary    url=http://127.0.0.1/openapi.json

Test Template       Wrapper


*** Test Cases ***
All Tests   # This test is deleted by DataDriver
    Wrapper    test_case_1


*** Keywords ***
Wrapper
    [Arguments]    ${case}
    Call And Validate    ${case}

```

# Authentication

## Dynamic token authentication
Library currently supports Schemathesis
[dynamic token](https://schemathesis.readthedocs.io/en/stable/guides/auth/#dynamic-token-authentication)
authentication by the library import `auth` argument. The dynamic token generation
class should follow the Schemathesis documentation. The only addition is the import.
Importing the class must follow the Robot Framework library
[import rules](https://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#specifying-library-to-import)
, example if importing with filename, filename much match to the class name. Example
if test case looks like:

```robotframework
*** Settings ***
Library             SchemathesisLibrary    url=http://127.0.0.1/openapi.json    auth=${CURDIR}/AuthExtension.py
Test Template       Wrapper

*** Test Cases ***
All Tests
    Wrapper    test_case_1

*** Keywords ***
Wrapper
    [Arguments]    ${case}
    Call And Validate    ${case}
```
And `AuthExtension.py` looks like
```python
from base64 import b64encode

import schemathesis
from robot.api import logger


@schemathesis.auth()
class AuthExtension:
    def get(self, case, ctx):
        # Instead of hard coding secrets to class, it is better to get them dynamically.
        # Jenkins or GitHub secrets, Azure keyvault, or from somewhere which is appropriate
        # for your needs.
        return b64encode("joulu:pukki".encode("utf-8")).decode("ascii")

    def set(self, case, data, ctx):
        case.headers = case.headers or {}
        case.headers["Authorization"] = f"Basic {data}"
        logger.debug(f"Updated headers for case: {case.operation.method} {case.operation.path}")
```
Then with all API calls, will have
[basic auth](https://en.wikipedia.org/wiki/Basic_access_authentication) set in the
headers for all calls made to your API endpoint.

# Schemathesis hook support
Library supports extending Schemathesis by defining hooks. Hooks allows users to customize how
Schemathesis generates test data, validates responses, and handles requests through hooks, custom
checks, and data generation strategies. For more details about Schemathesis hooks, refer to
Schemathesis extending documentation: https://schemathesis.readthedocs.io/en/stable/guides/extending/

Example if there need to add custom header in each request, then it is possible to import library
with hook:

```robotframework
*** Settings ***
Variables           authentication.py
Library             SchemathesisLibrary
...                     url=http://127.0.0.1/openapi.json
...                     hook=${CURDIR}/hook_filter.py

Test Template       Wrapper


*** Test Cases ***
All Tests
    Wrapper    test_case_1


*** Keywords ***
Wrapper
    [Arguments]    ${case}
    Call And Validate    ${case}    auth=${BASIC_AUTH_TUPLE}

```

And when hook_filter.py looks like:

```python
import schemathesis


global_count_count = 0


@schemathesis.hook
def filter_query(ctx, query) -> bool:
    method = ctx.operation.method.lower().strip()
    if method == "put":
        global global_count_count
        global_count_count += 1
        if global_count_count > 2:
            return False
    return True
```
Then only two test with `PUT` request are generated.
