Test Generation Steps

This is a reference for instances of Step used in test generation. They are used when implementing a step hook or a plan hook.

All steps can be imported from kolo.generate_tests.steps.

AssertDelete

The AssertDelete step represents an assertion that no instances of a Django model exist.

AssertDelete.module

The module where the Django model lives. For example, "django.contrib.auth.models".

AssertDelete.model

The name of the Django model. For example, "User".

AssertDelete.fields

A list of DjangoField instances used to specify which model instances do not exist.

AssertEqual

The AssertEqual step represents an assertion that two values are equal.

AssertEqual.left

The repr of a Python object to compare. For example "user.username".

AssertEqual.right

The repr of a Python object to compare. For example '"admin"'.

AssertEqual.imports

A set of Import instances used to add required imports to the generated test. Defaults to an empty set.

AssertInsert

The AssertInsert step represents an assertion that a Django model instance has been created.

AssertInsert.module

The module where the Django model lives. For example, "django.contrib.auth.models".

AssertInsert.model

The name of the Django model. For example, "User".

AssertInsert.lookup_fields

A list of DjangoField instances used to retrieve the model instance from the database.

AssertInsert.assert_fields

A list of DjangoField instances used to assert the inserted model has the correct values.

AssertInsert.defines_variable_name

A string representing the variable name created by this step. For example "user".

AssertResponseJson

The AssertResponseJson step represents an assertion that a response created by a DjangoTestClient step has a given json body.

AssertResponseJson.response_json

The expected body of the response, decoded from json.

AssertStatusCode

The AssertStatusCode step represents an assertion that a response created by a DjangoTestClient step has a given status code.

AssertStatusCode.status_code

The expected status code integer. For example, 200.

AssertTemplateUsed

The AssertTemplateUsed step represents an assertion that a response created by a DjangoTestClient step was generated using a particular template.

AssertTemplateUsed.template_name

The name of the template. For example, "users/profile.html".

AssertUpdate

The AssertUpdate step represents an assertion that a Django model instance has been updated.

AssertUpdate.model

The name of the Django model. For example, "User".

AssertUpdate.fields

A list of DjangoField instances used to assert the updated model has the correct values.

AssertUpdate.references_variable_name

A string representing the variable name used by this step. For example "user". This is expected to be created by an earlier step.

Code

The Code step represents an arbitrary chunk of code. It can be used when no other step is suitable.

Code.code

A string representing the code.

Code.imports

A set of Import instances used to add required imports to the generated test. Defaults to an empty set.

CodeComment

The CodeComment step represents a comment in the source code of the generated test.

CodeComment.comment

The text of the comment. For example, "Generated by Kolo".

DjangoTestClient

The DjangoTestClient step represents a call to the Django test client.

DjangoTestClient.method

The name of the http method used by the request. For example, get or post.

DjangoTestClient.path_info

The url fragment for the view being called by the test client. For example, "/users/".

DjangoTestClient.query_params

The request params used by a GET call. For example, {"name": "Kolo"}.

DjangoTestClient.request_body

The request body used by a POST, PUT or PATCH call. For example, {"name": "Kolo"}.

DjangoTestClient.headers.

A dictionary containing any request headers to include in the test client call. For example, {"user-agent": "curl/7.79.1"}.

EmptyLine

The EmptyLine step represents an empty line of source code in the generated test.

FactoryCreate

The FactoryCreate step represents the creation of a Django model instance with a factory boy factory.

FactoryCreate.module

The module where the factory lives. For example, "users.tests.factories".

FactoryCreate.factory

The name of the factory. For example, "UserFactory".

FactoryCreate.fields

A list of DjangoField instances defining the created model instance.

FactoryCreate.defines_variable_name

A string representing the variable name created by this step. For example "user".

ModelCreate

The ModelCreate step represents the creation of a Django model instance.

ModelCreate.module

The module where the model lives. For example, "django.contrib.auth.models".

ModelCreate.model

The name of the model. For example, "User".

ModelCreate.fields

A list of DjangoField instances defining the created model instance.

ModelCreate.defaults

A list of DjangoField instances passed as the defaults argument to get_or_create.

ModelCreate.defines_variable_name

A string representing the variable name created by this step. For example "user".

ModelCreate.method

The name of the Django manager method used to create the model. Defaults to get_or_create.

ModelUpdate

The ModelUpdate step represents an update to an already created Django model.

ModelUpdate.model

The name of the Django model. For example, "User".

ModelUpdate.fields

A list of DjangoField instances used to update the model.

ModelUpdate.references_variable_name

A string representing the variable name used by this step. For example "user". This is expected to be created by a ModelCreate step.

ModuleImports

The ModuleImports step represents a location in the generated test where imports defined by other steps should be placed.

RegisterMocket

The RegisterMocket step represents the configuration of mocket to mock http calls.

RegisterMocket.method

The http method of the mocked endpoint. For example, GET.

RegisterMocket.url

The url of the mocked endpoint. For example, "https://example.com".

RegisterMocket.status_code

The status code for mocket to return. For example, 200.

RegisterMocket.body

The body of the mocked response. For example, "<p>Hello world!</p>". Defaults to None.

RegisterMocket.json_body

The body of the mocked response for a json endpoint. This should be a python object that can be serialized as json. For example, {"foo": False}. Defaults to None.

RegisterMocket.content_type

The content type of the mocked response. For example, "text/plain". Defaults to "".

StartTimeTravel

The StartTimeTravel represents a context manager configuring time-machine or freezegun to mock time during the generated test. It must always be paired with an EndTimeTravel step to mark the end of the indented block.

StartTimeTravel.call

The time travel function to call. Either time_machine.travel or freezegun.freeze_time.

StartTimeTravel.args

A tuple containing the function arguments to the time travel function. For example, ('"2024-05-29T12:54:42"',) or ('"2024-05-29T12:54:42"', "tick=True").

StartTimeTravel.imports

A set of Import instances used to add required imports to the generated test. Either {Import("import time_machine")} or {Import("import freezegun")}.

TestClass

The TestClass step represents a test class in the unittest style. It must always be paired with an EndTestClass step to mark the end of the indented block.

TestClass.name

The name of the generated test class. For example, "MyTestCase".

TestClass.parents

A tuple containing the parent classes of the generated test class. For example, ("TestCase",).

TestClass.imports

A set of Import instances used to add required imports to the generated test. For example, {Import("from django.test import TestCase")}.

TestFunction

The TestFunction step represents a test function in the pytest style. It must always be paired with an EndTestFunction step to mark the end of the indented block.

TestFunction.name

The name of the test function. For example, "test_my_view".

TestFunction.fixtures

A tuple containing any pytest fixtures for use in the test. For example, ("client",).

TestMethod

The TestMethod step represents a test method in the unittest style. It must always be paired with an EndTestMethod step to mark the end of the indented block.

TestMethod.name

The name of the test method. Defaults to "test_my_view".

With

The With step represents a context manager. It must always be paired with an EndWith step to mark the end of the indented block.

With.call

The name of the context manager. For example, "pytest.raises".

With.args

A tuple containing any arguments passed to the context manager. For example, ("ValueError", 'match="must be 0 or None"').

With.defines_variable_name

A string representing the variable name created by this step. For example "exc_info".

With.imports

A set of Import instances used to add required imports to the generated test. For example, {Import("import pytest")}.

DjangoField

The DjangoField class is a helper class representing a Django field that is used by another step.

DjangoField.name

The name of the field. For example, "username".

DjangoField.value

The repr of the value of the field. For example, '"admin"'.

DjangoField.imports

A set of Import instances used to add required imports to the generated test. For example, {Import("from decimal import Decimal")}.

Import

The Import class is a helper class representing an import that will be included in the generated test by the ModuleImports step.

Import.import_path

The import to be include in the test. For example, "from datetime import date".

Step

The Step class can be subclassed to define a custom step.

Step.indent_delta

This class attribute marks a change in the indentation level of the generated code. Steps that start an indented block should set this to 1. Steps that end an indented block should set this to -1. All other steps can inherit the default value of 0.

Step.render

A Step subclass must define a render method that defines how that step should be rendered in the generated test. This method takes a boolean pytest argument to allow the rendered step to differ between pytest and unittest style tests. It must return a string.

For example:

from kolo.generate_tests.steps import Step


@dataclass()
class AssertGreater(Step):
    left: str
    right: str

    def render(self, pytest):
        if pytest:
            return f"assert {self.left} > {self.right}\n"
        return f"self.assertGreater({self.left}, {self.right})\n"

Step.get_imports

A Step subclass may define a get_imports method that returns a set of Import instances for inclusion in the generated test. This method takes a boolean pytest argument to allow different imports for pytest and unittest style tests.

For example:

from kolo.generate_tests.steps import Step


@dataclass()
class AssertTemplateNotUsed(Step):
    template_name: str

    def render(self, pytest):
        if pytest:
            assertTemplateNotUsed = "assertTemplateNotUsed"
        else:
            assertTemplateNotUsed = "self.assertTemplateNotUsed"
        return f"{assertTemplateNotUsed}(response, {repr(self.template_name)})\n"

    def get_imports(self, pytest):
        if pytest:
            return {Import("from pytest_django.asserts import assertTemplateNotUsed")}
        return set()

Step.get_steps

A Step subclass that represents the start of a section should define a get_steps classmethod that returns the start step, the end step and all steps in between. This is used to determine which steps are passed to a step_hook targetting this start step. The get_steps_slice helper function is available to make implementing this easy:

from kolo.generate_tests.steps import Step, get_steps_slice


@dataclass()
class Start(Step):
    indent_delta = 1

    @classmethod
    def get_steps(cls, steps):
        return get_steps_slice(cls, End, steps)


@dataclass()
class End(Step):
    indent_delta = -1