Skip to main content

jaffamonkey

Screenplay & Pytest

ScreenPy provides tools for writing automated test suites which follow the Screenplay Pattern. It encourages user-focused tests which are easy to read, understand, and maintain.

In this example, we are going to use ScreenPy with PyTest (which is a lean test framework) to test REST API endpoints.

Note: If you want to use allure reports, ensure allure is installed on your OS (for macos, it’s brew install allure).

Installation

Install file

requirements.txt

screenpy[requests,allure]>=4.2.0
pytest

Install packages

python -m venv env
source env/bin/activate
pip install -r requirements.txt

Tests files

Urls file

We are going to use the API test url https://httpsbin.org, for this test framework.

urls.py

""" URLs to be tested via API requests."""

BASE_URL = "https://httpbin.org"
BASIC_AUTH_URL = f"{BASE_URL}/basic-auth"
BEARER_AUTH_URL = f"{BASE_URL}/bearer"
SET_COOKIES_URL = f"{BASE_URL}/cookies/set"
BASE64_URL = f"{BASE_URL}/base64"

Auth Test

features/test_auth.py

"""
API test example that tests various auths.
"""

from screenpy import Actor, given, then, when
from screenpy.actions import See
from screenpy.resolutions import IsEqualTo
from screenpy_requests.actions import AddHeader, SendGETRequest
from screenpy_requests.questions import StatusCodeOfTheLastResponse

from ..urls import BASIC_AUTH_URL, BEARER_AUTH_URL


def test_basic_auth(Perry: Actor) -> None:
"""Basic authentication is accepted by the basic auth endpoint."""
test_username = "USER"
test_password = "PASS"

when(Perry).attempts_to(
SendGETRequest.to(f"{BASIC_AUTH_URL}/{test_username}/{test_password}").with_(
auth=(test_username, test_password)
)
)

then(Perry).should(See.the(StatusCodeOfTheLastResponse(), IsEqualTo(200)))


def test_bearer_auth(Perry: Actor) -> None:
"""Bearer token authentication is accepted by the bearer auth endpoint."""
given(Perry).was_able_to(AddHeader(Authorization="Bearer 1234"))

when(Perry).attempts_to(SendGETRequest.to(BEARER_AUTH_URL))

then(Perry).should(See.the(StatusCodeOfTheLastResponse(), IsEqualTo(200)))

Cookies Test

test_cookies.py

"""API test example that tests cookies."""

from screenpy import Actor, then, when
from screenpy.actions import SeeAllOf
from screenpy.resolutions import ContainTheEntry, IsEqualTo
from screenpy_requests.actions import SendGETRequest
from screenpy_requests.questions import Cookies, StatusCodeOfTheLastResponse

from ..urls import SET_COOKIES_URL


def test_set_cookies(Perry: Actor) -> None:
"""Cookies set by the set cookies endpoint appear on the session."""
test_cookie = {"type": "macaroon"}

when(Perry).attempts_to(
SendGETRequest.to(SET_COOKIES_URL).with_(params=test_cookie)
)

then(Perry).should(
SeeAllOf.the(
(StatusCodeOfTheLastResponse(), IsEqualTo(200)),
(Cookies(), ContainTheEntry(**test_cookie)),
)
)

Test methods

test_methods.py

"""API test examples that use all the HTTP methods."""

import pytest

from screenpy import Actor, then, when
from screenpy.actions import See
from screenpy.resolutions import IsEqualTo, ReadsExactly
from screenpy_requests.actions import SendAPIRequest, SendGETRequest
from screenpy_requests.questions import (
BodyOfTheLastResponse,
StatusCodeOfTheLastResponse,
)

from ..urls import BASE64_URL, BASE_URL


@pytest.mark.parametrize("action", ["DELETE", "GET", "PATCH", "POST", "PUT"])
def test_actions(action: str, Perry: Actor) -> None:
"""HTTP-action endpoints all respond with 200s."""
when(Perry).attempts_to(SendAPIRequest(action, f"{BASE_URL}/{action.lower()}"))

then(Perry).should(See.the(StatusCodeOfTheLastResponse(), IsEqualTo(200)))


def test_base64_decoder(Perry: Actor) -> None:
"""Base64 decoder correctly decodes string"""
test_string = "QSBsb25nIHRpbWUgYWdvIGluIGEgZ2FsYXh5IGZhciwgZmFyIGF3YXk="

when(Perry).attempts_to(SendGETRequest.to(f"{BASE64_URL}/{test_string}"))

then(Perry).should(
See.the(StatusCodeOfTheLastResponse(), IsEqualTo(200)),
See.the(
BodyOfTheLastResponse(),
ReadsExactly("A long time ago in a galaxy far, far away"),
),
)

Run tests

To run the tests, call the following in the project root folder:

python -m pytest features/

To run the tests with Allure reporting:

python -m pytest features/ --alluredir allure_report/
allure serve allure_report

Allure report

Allure report for Pytest API test run

More resources

Here are a couple more resources, or check out the full list.

  1. Superagent API testing

    Superagent is a small progressive client-side HTTP request library, and Node.js module with the same API, supporting many high-level HTTP client features.

  2. Artillery load test

    Artillery is a scalable, flexible and easy-to-use platform that contains everything you need for production-grade load testing.