UnitTest support¶
Tortoise ORM includes its own helper utilities to assist in unit tests.
Usage¶
from tortoise.contrib import test
class TestSomething(test.TestCase):
def test_something(self):
...
async def test_something_async(self):
...
@test.skip('Skip this')
def test_skip(self):
...
@test.expectedFailure
def test_something(self):
...
To get test.TestCase
to work as expected, you need to configure your test environment setup and teardown to call the following:
from tortoise.contrib.test import initializer, finalizer
# In setup
initializer(['module.a', 'module.b.c'])
# With optional db_url, app_label and loop parameters
initializer(['module.a', 'module.b.c'], db_url='...', app_label="someapp", loop=loop)
# Or env-var driven → See Green test runner section below.
env_initializer()
# In teardown
finalizer()
On the DB_URL it should follow the following standard:
TORTOISE_TEST_DB=sqlite:///tmp/test-{}.sqlite TORTOISE_TEST_DB=postgres://postgres:@127.0.0.1:5432/test_{}
The {}
is a string-replacement parameter, that will create a randomized database name.
This is currently required for test.IsolatedTestCase
to function.
If you don’t use test.IsolatedTestCase
then you can give an absolute address.
The SQLite in-memory :memory:
database will always work, and is the default.
Test Runners¶
Green¶
In your .green
file:
initializer = tortoise.contrib.test.env_initializer
finalizer = tortoise.contrib.test.finalizer
And then define the TORTOISE_TEST_MODULES
environment variable with a comma separated list of module paths.
Furthermore, you may set the database configuration parameter as an environment variable (defaults to sqlite://:memory:
):
TORTOISE_TEST_DB=sqlite:///tmp/test-{}.sqlite TORTOISE_TEST_DB=postgres://postgres:@127.0.0.1:5432/test_{}
Py.test¶
Note
pytest 5.4.0 & 5.4.1 has a bug that stops it from working with async test cases. You may have to install pytest>=5.4.2
to get it to work.
Run the initializer and finalizer in your conftest.py
file:
import os
import pytest
from tortoise.contrib.test import finalizer, initializer
@pytest.fixture(scope="session", autouse=True)
def initialize_tests(request):
db_url = os.environ.get("TORTOISE_TEST_DB", "sqlite://:memory:")
initializer(["tests.testmodels"], db_url=db_url, app_label="models")
request.addfinalizer(finalizer)
Nose2¶
Load the plugin tortoise.contrib.test.nose2
either via command line:
nose2 --plugin tortoise.contrib.test.nose2 --db-module tortoise.tests.testmodels
Or via the config file:
[unittest]
plugins = tortoise.contrib.test.nose2
[tortoise]
# Must specify at least one module path
db-module =
tests.testmodels
# You can optionally override the db_url here
db-url = sqlite://testdb-{}.sqlite
Reference¶
-
class tortoise.contrib.test.IsolatedTestCase(methodName=
'runTest'
)[source]¶ Bases:
SimpleTestCase
An asyncio capable test class that will ensure that an isolated test db is available for each test.
Use this if your test needs perfect isolation.
Note to use
{}
as a string-replacement parameter, for your DB_URL. That will create a randomised database name.It will create and destroy a new DB instance for every test. This is obviously slow, but guarantees a fresh DB.
If you define a
tortoise_test_modules
list, it overrides the DB setup module for the tests.-
tortoise_test_modules : Iterable[str | module] =
[]
¶
-
tortoise_test_modules : Iterable[str | module] =
-
class tortoise.contrib.test.SimpleTestCase(methodName=
'runTest'
)[source]¶ Bases:
IsolatedAsyncioTestCase
The Tortoise base test class.
This will ensure that your DB environment has a test double set up for use.
An asyncio capable test class that provides some helper functions.
Will run any
test_*()
function either as sync or async, depending on the signature of the function. If you specifyasync test_*()
then it will run it in an event loop.Based on asynctest
- exception tortoise.contrib.test.SkipTest[source]¶
Bases:
Exception
Raise this exception in a test to skip it.
Usually you can use TestCase.skipTest() or one of the skipping decorators instead of raising this directly.
-
class tortoise.contrib.test.TestCase(methodName=
'runTest'
)[source]¶ Bases:
TruncationTestCase
An asyncio capable test class that will ensure that each test will be run at separate transaction that will rollback on finish.
This is a fast test runner. Don’t use it if your test uses transactions.
-
class tortoise.contrib.test.TruncationTestCase(methodName=
'runTest'
)[source]¶ Bases:
SimpleTestCase
An asyncio capable test class that will truncate the tables after a test.
Use this when your tests contain transactions.
This is slower than
TestCase
but faster thanIsolatedTestCase
. Note that usage of this does not guarantee that auto-number-pks will be reset to 1.
- tortoise.contrib.test.env_initializer()[source]¶
Calls
initializer()
with parameters mapped from environment variables.TORTOISE_TEST_MODULES
:A comma-separated list of modules to include (required)
TORTOISE_TEST_APP
:The name of the APP to initialise the modules in (optional)
If not provided, it will default to “models”.
TORTOISE_TEST_DB
:The db_url of the test db. (optional)
If not provided, it will default to an in-memory SQLite DB.
- Return type:¶
None
- tortoise.contrib.test.expectedFailure(test_item)[source]¶
Mark test as expecting failure.
On success it will be marked as unexpected success.
- tortoise.contrib.test.finalizer()[source]¶
Cleans up the DB after testing. Must be called as part of the test environment teardown.
- Return type:¶
None
- tortoise.contrib.test.getDBConfig(app_label, modules)[source]¶
DB Config factory, for use in testing.
-
tortoise.contrib.test.init_memory_sqlite(models: str | list[str] | None =
None
) Callable[[...], Callable[[P], Coroutine[None, None, T]]] [source]¶ - tortoise.contrib.test.init_memory_sqlite(models: Callable[[P], Coroutine[None, None, T]]) Callable[[P], Coroutine[None, None, T]]
For single file style to run code with memory sqlite
- Parameters:¶
- models: str | list[str] | None =
None
¶ - models: Callable[[P], Coroutine[None, None, T]]
list_of_modules that should be discovered for models, default to [‘__main__’].
- models: str | list[str] | None =
Usage:
from tortoise import fields, models, run_async from tortoise.contrib.test import init_memory_sqlite class MyModel(models.Model): id = fields.IntField(primary_key=True) name = fields.TextField() @init_memory_sqlite async def run(): obj = await MyModel.create(name='') assert obj.id == 1 if __name__ == '__main__' run_async(run)
Custom models example:
@init_memory_sqlite(models=['app.models', 'aerich.models']) async def run(): ...
- Return type:¶
Union
[Callable
[[~P],Coroutine
[None
,None
, ~T]],Callable
[…,Callable
[[~P],Coroutine
[None
,None
, ~T]]]]
-
tortoise.contrib.test.initializer(modules, db_url=
None
, app_label='models'
, loop=None
)[source]¶ Sets up the DB for testing. Must be called as part of test environment setup.
-
tortoise.contrib.test.requireCapability(connection_name=
'models'
, **conditions)[source]¶ Skip a test if the required capabilities are not matched.
Note
The database must be initialized before the decorated test runs.
Usage:
@requireCapability(dialect='sqlite') async def test_run_sqlite_only(self): ...
Or to conditionally skip a class:
@requireCapability(dialect='sqlite') class TestSqlite(test.TestCase): ...