Metadata-Version: 2.4
Name: swaggerforge
Version: 0.3.1
Summary: Automatic pytest test generation from OpenAPI (Swagger) specifications
Author: Viktor Pylypenko
License-Expression: MIT
Keywords: openapi,swagger,pytest,test generation,api testing
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: click>=8.0
Requires-Dist: prance>=23.6.21.0
Requires-Dist: openapi-spec-validator>=0.7
Requires-Dist: jinja2>=3.0
Requires-Dist: requests>=2.28
Requires-Dist: jsonschema>=4.0
Requires-Dist: tomli>=2.0; python_version < "3.11"
Provides-Extra: dev
Requires-Dist: pytest>=9.0; extra == "dev"
Requires-Dist: flake8>=7.0; extra == "dev"
Requires-Dist: pytest-cov>=7.0; extra == "dev"
Requires-Dist: tox>=4.0; extra == "dev"
Provides-Extra: oauth2
Requires-Dist: requests-oauth2client>=1.6; extra == "oauth2"
Dynamic: license-file

# SwaggerForge

Automatic pytest test generation from OpenAPI (Swagger) specifications.

SwaggerForge is a Python library and command-line tool that reads an OpenAPI
specification and generates ready-to-run pytest test files - one per resource
covering positive, negative, boundary, and boolean scenarios grounded in
established test-design techniques.

## Features

- Reads OpenAPI 3.x specifications in JSON or YAML
- Resolves `$ref` references automatically
- Generates one pytest file per resource tag
- Produces six scenario types per endpoint where applicable:
  - **Positive** >>> valid request, expects a 2xx response and validates the
    response schema
  - **Missing required field** >>> omits a required field, expects 400
  - **Wrong data type** >>> sends a mistyped field, expects 400/422
  - **Nonexistent resource** >>> requests an unlikely identifier, expects 404
  - **Boundary values** >>> tests values at and just beyond declared
    numeric/length limits (Boundary Value Analysis)
  - **Boolean coverage** >>> exercises both `true` and `false` for boolean fields
- Deterministic output: the same specification always produces identical tests
- Generated files use session-scoped pytest fixtures and run with no manual edits
- Optional `swaggerforge.toml` config file for project-level defaults
- Comprehensive authentication: bearer, basic, API key (header/query/cookie),
  multiple-scheme AND/OR requirements, and OAuth2 / OpenID Connect (optional
  extra), with environment-variable substitution for secrets

## Requirements

- Python 3.10 or newer

## Installation

```bash
pip install swaggerforge
```

## Usage

Generate tests from a specification, pointing at the base URL of the API
under test:

```bash
swaggerforge generate --spec swagger.json --url http://localhost:8080
```

This reads `swagger.json`, writes one `test_<resource>.py` file per resource
tag into the output directory (default: `tests_generated/`), and the files can
be run immediately:

```bash
pytest tests_generated
```

### Options

| Option     | Description                                        | Default                           |
|------------|----------------------------------------------------|-----------------------------------|
| `--spec`   | Path to the OpenAPI specification (JSON or YAML)   | *(required)*                      |
| `--url`    | Base URL of the API under test                     | *(required unless in config)*     |
| `--output` | Directory for the generated test files             | `tests_generated`                 |
| `--config` | Path to a configuration file                       | `./swaggerforge.toml` if present  |

## Configuration

Options that stay the same across runs can be kept in a `swaggerforge.toml`
file instead of being passed on the command line. The file is picked up
automatically from the directory where the tool is run, or an explicit path
can be given with `--config`.

```toml
# swaggerforge.toml
base_url = "http://localhost:8080"
output_dir = "tests_generated"
timeout = 30
```

| Key          | Type    | Effect                                                        |
|--------------|---------|---------------------------------------------------------------|
| `base_url`   | string  | Base URL of the API; makes `--url` optional                   |
| `output_dir` | string  | Directory for generated files                                 |
| `timeout`    | integer | Embeds `timeout=<n>` into every generated HTTP request call   |

Values given on the command line always take precedence over the config file.
Without a `timeout`, generated tests place no time limit on requests -
setting one makes test runs fail fast when the API is unreachable.

## Authentication

When a specification declares security requirements, SwaggerForge configures
the generated tests to authenticate. Credentials are supplied through the
config file; the specification decides *which* scheme and *where* each value
goes, and the config supplies the secret values.

```toml
# swaggerforge.toml
[auth.bearer]
token = "${API_TOKEN}"

[auth.api_key]
value = "${API_KEY}"

[auth.basic]
username = "${API_USER}"
password = "${API_PASSWORD}"

[auth.oauth2]
client_id = "${OAUTH_CLIENT_ID}"
client_secret = "${OAUTH_CLIENT_SECRET}"
scope = "read write"
```

Generated tests build a session-scoped `requests.Session` that carries the
resolved authentication, so every request is authenticated without repeating
credentials per call.

### Supported schemes

| Config section  | OpenAPI scheme                              | How it is applied                                   |
|-----------------|---------------------------------------------|-----------------------------------------------------|
| `[auth.bearer]` | `http` bearer                               | `Authorization: Bearer <token>` header              |
| `[auth.api_key]`| `apiKey` in header, query, or cookie        | the name and location declared by the specification |
| `[auth.basic]`  | `http` basic                                | `Authorization: Basic <base64>` header              |
| `[auth.oauth2]` | `oauth2` client credentials, `openIdConnect`| a token fetched at runtime (see below)              |

For an API key, both the **name** and the **location** (header, query, or
cookie) come from the specification; the config supplies only the secret
`value`.

### Multiple schemes

OpenAPI can require several schemes at once (AND) or offer alternatives (OR).
SwaggerForge honours both: it uses the first alternative whose credentials are
fully configured, combining every scheme in an AND group. When endpoints in one
file need different authentication, the differing ones override the session per
request.

### OAuth2 and OpenID Connect

OAuth2 and OIDC support is an optional extra, installed with:

```bash
pip install swaggerforge[oauth2]
```

For the **client credentials** flow, generated tests fetch a fresh access
token from the specification's `tokenUrl` at runtime (and refresh it on
expiry), so no token is ever embedded at generation time. **OpenID Connect**
schemes work the same way, discovering the token endpoint at runtime from the
specification's `openIdConnectUrl`. Both need `client_id` and `client_secret`
in `[auth.oauth2]`.

Interactive flows (OAuth2 **authorization code**) require a human to log in
through a browser and so cannot be fully automated. For these, SwaggerForge
generates a clearly marked placeholder in the session fixture where you paste a
token obtained manually.

### Environment variables and missing credentials

Any auth value may reference an environment variable with `${VAR}` syntax, so
secrets stay out of the config file; a referenced variable that is not set is
an error. If a specification requires a scheme whose credentials are not
configured, SwaggerForge prints a warning naming the scheme and generates the
tests without that authentication rather than failing.

## How it works

SwaggerForge runs a six-stage pipeline: the specification is validated, parsed
into an internal model (with `$ref`s resolved), turned into test scenarios
based on test-design techniques, rendered into pytest code via templates, and
written to per-resource files.

## Limitations

- Targets OpenAPI 3.x with JSON request bodies
- Authentication covers bearer, basic, API key (header/query/cookie), OAuth2
  client credentials, and OpenID Connect; interactive OAuth2 flows
  (authorization code) generate a placeholder for a manually obtained token,
  as they require a browser-based login that cannot be automated
- Boundary tests require the specification to declare numeric/length constraints

## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file.
