Skip to content

Running tests and linting

Your business logic should of course be covered by unit tests. When generating code using lime-project generate the result includes boilerplate tests, where you can add your own tests. For Python we are using pytest and our own pytest plugin lime-test. For Web Components we are using Stencils test framework which uses Jest, and some helpers from @lundalogik/limeclient.js to help create an environment that is similar to a real application.

In Lime projects we are also using linting tools to catch common code mistakes and follow a shared set of formatting rules.
For Python we are using flake8 and for Web Components we are using ESLint.


Our standard CI toolchain will fail any build containing any test or lint error.


Running tests

To run your Python tests with pytest use:

poetry run pytest .

VS Code can be configured to discover and run the tests.

Linting and formatting


To lint you Python code with flake8 use:

poetry run flake8 .

VS Code can be configured to automatically lint your code.


We also recommend formatting the code with black, which will format your code according to a set of formatting rules.

If you have black installed you can either use it to check your code for inconsistencies with regards to the formatting rules, or run the automatic formatting.

Checking your code:

poetry run black . --check

Formatting your code:

poetry run black .


Another recommended formatting tool is isort, which will sort and format the import statements in your python files.

If you have isort installed it can also be used to check your code or run automatic formatting.

Checking your code:

poetry run isort . --check

Formatting your code:

poetry run isort .

The lime-test framework

lime-test helps you write tests for code that makes use of the Lime CRM platform, such as plugins or non-core packages.
It's implemented as a plugin to pytest, which gives you a set of ready made fixtures that you can use for the more basic types of tests for Lime.
For more control, you are encouraged to use the available helper functions that allows you to create more pointed test code.

The following example uses the core_app fixture, which loads a complete LimeApplication (lime_application.application.LimeApplication) with a set of lime types defined that closely matches the current state of the lime-core database.
It also loads a complete database to memory that is disregarded after the test ends to ensure that multiple tests don't interfere with each other.

The code we want to test:

def average(limeobjects, propname):
    values = [o.get_property(propname).value for o in limeobjects]
    return sum(values) / len(values)

The code we can use to test it:

def test_average(core_app):
    Deal =
    deals = [
    assert average(deals, 'value') == 3


lime-test is implemented as a plugin to pytest, which means that as soon as it's installed, it will contain fixtures to be used to set up the conditions for your tests more quickly. These fixtures are more often than not to be considered a starting point, and you'll most likely find yourself in need of more fine grained control over your test setups.

To use a fixture in your tests, do this:

def test_my_app(core_app):
    uow = core_app.unit_of_work()

    assert len(list( == 1

Defining data structures

In order for your tests to be manageable, it's essential to distinctly be able to define and read what types are expected of your code. To help with this, lime-test makes use of lime-core's ability to express data structures as dicts or YAML-documents.

The following shows an example of a fixture that sets up an empty database with a coworker and a company that relates to each other. It is recommended to use a separate YAML file for the database structure so it can be reused for testing web components in the frontend.

    name: string
        type: option
            - poor
            - good
            - excellent
        type: belongsto
        related: coworker
        backref: companies
        type: hasmany
        related: company
        backref: responsible
def my_database(empty_database):
    with open("dsl.yaml", "r") as file:
        types =

    limetypes = lime_type.create_limetypes_from_dsl(types)
    lime_test.db.add_limetypes(empty_database, limetypes)
    return empty_database

For more detailed information see lime_type.create_limetypes_from_dsl. It's also possible to define object instances to use in your tests by using lime_type.create_limeobjects_from_dsl.

In-memory Web Application

lime-test enables you to start up a complete web application in memory that you can make requests to to ensure that your endpoints work as they should. It builds on the in memory database to create a complete environment for your endpoints that is created for your specific test method, and teared down immediately afterwards.

It's an implementation of Flasks's test server

A simple example

Given the following endpoint:

class DealAverage(webserver.LimeResource):
    def get(self, companyid):
        company =
        avg = averagelib.average(, 'value')

        return {'average': avg}

api.add_resource(DealAverage, '/dealaverage/<int:companyid>')

We can write the following test:

def test_calculate_average_for_deals(webapp, limeapp):
    Company =
    Deal =

    uow = limeapp.unit_of_work()

    acme = Company(name='acme')
    acme_idx = uow.add(acme)

    deals = [
        Deal(name='deal1', value=42),
        Deal(name='deal2', value=128),
    for d in deals:

    res = uow.commit()

    acme = res[acme_idx]

    res = webapp.get('/myapp/acme_solution/dealaverage/{}'

    json_response = json.loads('utf-8'))
    assert res.status_code == 200
    assert json_response == {'average': 85.0}