Skip to content

Integration tests

Integration tests are Python tests that run against SQL Server instead of the in-memory database that unit tests use. They live in a top-level integration_tests/ folder and run with the --load-lime-test-integration-plugin option. They are optional: a project without the folder is complete.

Version requirement

The --load-lime-test-integration-plugin option requires lime-core 26.80.2 or later, which is bundled in lime-crm v3.82.0 and later.

When do you need integration tests?

Unit tests run against an in-memory database. That is fast and needs no setup, and it is the right choice for most business logic.

Write an integration test when the code under test depends on database behavior that the in-memory database does not reproduce, and you need to see it work against SQL Server.

Where do integration tests live?

Put integration tests in a folder named integration_tests in the root of the project, next to tests:

limepkg-my-package/
├── integration_tests/
│   ├── conftest.py
│   └── test_company_sync.py
├── limepkg_my_package/
├── tests/
│   ├── conftest.py
│   └── test_insanity.py
└── pyproject.toml

lime-project does not create the folder. Create it yourself when you write the first integration test.

Then make sure integration_tests is listed in norecursedirs in pyproject.toml, so that poetry run pytest skips the folder:

[tool.pytest.ini_options]
minversion = '6.0'
norecursedirs = [
    'venv',
    '.venv',
    'build',
    'dist',
    '.plugins',
    'frontend',
    'integration_tests',
    '.env',
    '.git',
    '.github',
    '.lime',
    '.vscode'
]

Without that entry, poetry run pytest also runs the integration tests, against the in-memory database.

How to run integration tests locally

You need two things on your machine:

Run the tests from the root of the project:

poetry run pytest integration_tests --load-lime-test-integration-plugin

The first run takes longer, because Docker downloads the SQL Server image.

Do not add the option to addopts

Adding --load-lime-test-integration-plugin to addopts in pyproject.toml makes every test run need SQL Server, including the unit tests in tests/. The tests then pass on a machine with Docker and the ODBC driver, and fail elsewhere with an error like Can't open lib 'ODBC Driver 18 for SQL Server'.

Pass the option on the command line, and only together with the integration_tests folder.

How to write an integration test

An integration test looks like a unit test and uses the same fixtures, such as lime_app and save_lime_objects:

def test_company_is_saved(lime_app, save_lime_objects):
    company = lime_app.limetypes.company(name="Acme")

    saved = save_lime_objects(company)

    assert saved.id is not None

How do integration tests differ from unit tests?

The fixtures are used the same way in both kinds of tests, with these differences:

Unit tests Integration tests
database In-memory database SQL Server
Data saved by a test Gone when the test ends Still there when the next test runs
create_limetype_tables Available Not supported — using it fails the test

Because data stays between integration tests, a test must not assume that the database is empty unless you clean up after each test.

How to clean up data between integration tests

To remove the data a test leaves behind, define a fixture named mssql_truncate_tables that returns the tables to empty after each test. The table of a limetype has the same name as the limetype:

import pytest


@pytest.fixture(autouse=True)
def mssql_truncate_tables() -> list[str]:
    return ["company", "person"]

Put the fixture in integration_tests/conftest.py to apply it to every integration test, or in a test module to apply it to that module only.

To drop tables instead of emptying them, define a fixture named mssql_delete_tables the same way. Both fixtures accept table names and compiled regular expressions:

import re

import pytest


@pytest.fixture(autouse=True)
def mssql_delete_tables() -> list[re.Pattern]:
    return [re.compile(r"my_temporary_.+")]

How to share fixtures between tests and integration_tests

pytest only applies a conftest.py to the tests in the same folder and below it. Fixtures in tests/conftest.py are therefore not available in integration_tests/.

To use the same fixtures in both folders, move them to a conftest.py in the root of the project:

limepkg-my-package/
├── conftest.py              # fixtures for both folders
├── integration_tests/
│   └── conftest.py          # fixtures for integration tests only
├── tests/
│   └── conftest.py          # fixtures for unit tests only
└── pyproject.toml

A fixture in the root conftest.py is used by both kinds of tests, so it must only rely on fixtures that work in both. For example, it cannot use create_limetype_tables.