The Avrae test suite is comprised of three primary parts: end-to-end (E2E) testing (e2e/), unit testing (unit/), and
gamedata simulation testing (gamedata/).
(venv) $ pip install -r tests/requirements.txtThe test environment requires MongoDB and Redis to be set up to facilitate the E2E tests. You can either use Docker
and the docker-compose.ci.yml Compose file, or set up these services and the following environment variables yourself:
NO_DICECLOUD: Set this to1. This disables the Dicecloud client which would otherwise try to connect on startup.DISCORD_OWNER_USER_ID: This can be any random number.MONGO_URL: A MongoDB connection url.REDIS_URL: A Redis connection url.
In order to run the gamedata simulation tests, you'll also need to set the following environment variables:
TEST_GAMEDATA_BASE_PATH: A path to the directory containing the canonical gamedata. Defaults totests/static/compendium.TEST_SIMULATION_BASE_PATH: A path to the directory containing the simulation files under test (actions.json,monsters.json,spells.json). Defaults totests/static/compendium.
Once all the environment variables have been set, you can run the tests with:
(venv) $ pytestIf you have set the gamedata tests to point to real gamedata, this will run over 55,000 tests! To filter this, a number of pytest marks are provided to allow filtering the tests:
e2eunitgamedatasimulation
Use the -m flag to select the marks to run. For example, to select only the non-gamedata tests, you could
use pytest -m "not gamedata".
Running tests with docker is very simple. Once you have docker set-up as shown in the README, you can run the following:
docker compose down && docker compose -f docker-compose.ci.yml up -d --build && docker logs -f avrae-tests-1This will shut down your current Avrae instance (resetting the database), run the tests, and open the test logs.
Pytest will automatically discover test files in the tests/ directory, as long as the file is named in the pattern of
*_test.py. Inside each test file, a test is comprised of a function named test_*(). See the pytest docs for more
information.
Unit tests test a unit of code - usually one function or method - and run assertions on the outputs of that function given its inputs. They're usually the right kind of test for parsing, utility functions, and self-contained units.
To add a new unit test, add it to the tests/unit directory, using the other unit test files as an example.
These are the preferred test type in general because they encourage good code encapsulation.
End-to-end tests test the entire system, as opposed to a single unit of code. Generally, these tests function by sending a fake Discord message to Avrae, then watching what Avrae would send back to Discord and running assertions on this output. E2E tests can also run assertions on state after Avrae finishes processing a message by using helpers to retrieve character or combat state.
E2E tests depend on two primary fixtures:
avraeis the instance of the bot, with a couple of utility methods monkey-patched in.- Use
avrae.message("!command")to send mock Discord messages to Avrae during E2E tests.
- Use
dhttpis the mock Discord HTTP client, which records the HTTP requests Avrae would have made to the Discord API.- Use
await dhttp.receive_*to run assertions on the requests Avrae would make to Discord. - For example,
await dhttp.receive_message("Hello world")would require Avrae to send a message with the contentHello world.dhttpmethods contain arguments to help loosely match content - seetests/mocks.pyand other E2E tests for examples.
- Use
tests/utils.py contains multiple helpers to assist writing E2E tests.
Gamedata tests run simulations on every official automation document in order to ensure that there are no errors in the Automation Engine. Generally, these are added by writing more official automation, rather than gamedata tests.
As these tests operate on non-SRD data, care must be taken not to expose the underlying data in the tests. For PRs
opened by outside contributors, a project maintainer must approve the gamedata test workflow by commenting
/ci-approve on the PR.
dhttp: The mock Discord client, used to run assertions on bot output. See E2E Tests above.avrae: The Avrae instance, used to send mock messages. See E2E Tests above.character: A parameterized fixture that provides various Character objects and sets the yielded character as the active character in the test db.init_fixture: A fixture that should be used at the class scope to clean up after a group if initiative tests.
spells: A fixture providing the entirety ofspells.json.monsters: A fixture providing the entirety ofmonsters.json.actions: A fixture providing the entirety ofactions.json.spell: A parameterized fixture providing each spell inspells.jsonindividually.monster: A parameterized fixture providing each monster inmonsters.jsonindividually.monster_attack: A parameterized fixture providing each attack of each monster inmonsters.jsonindividually.action: A parameterized fixture providing each action inactions.jsonindividually.bob: A generic StatBlock caster that includes spellcasting information.ara: A Character caster (level 10 Bard/Warlock). Does not set up the DB (c.f.character).mock_combat: A fixture that provides an ephemeral Combat instance for use in simulation tests without having to start a combat using E2E methods.