*Unit testing* means testing components of a program in isolation from each other to make sure every part works on its own before using it with others. Extensive testing helps avoid new updates causing unexpected side effects as well as alleviates general code rot (a more comprehensive wikipedia article on unit testing can be found [here](https://en.wikipedia.org/wiki/Unit_test)).
A typical unit test set calls some function or method with a given input, looks at the result and makes sure that this result looks as expected. Rather than having lots of stand-alone test programs, Evennia makes use of a central *test runner*. This is a program that gathers all available tests all over the Evennia source code (called *test suites*) and runs them all in one go. Errors and tracebacks are reported.
If you want to help out writing unittests for Evennia, take a look at Evennia's [coveralls.io
page](https://coveralls.io/github/evennia/evennia). There you see which modules have any form of
test coverage and which does not. All help is appreciated!
### Unit testing contribs with custom models
A special case is if you were to create a contribution to go to the `evennia/contrib` folder that
uses its [own database models](../Concepts/Models.md). The problem with this is that Evennia (and Django) will
only recognize models in `settings.INSTALLED_APPS`. If a user wants to use your contrib, they will
be required to add your models to their settings file. But since contribs are optional you cannot
add the model to Evennia's central `settings_default.py` file - this would always create your
optional models regardless of if the user wants them. But at the same time a contribution is a part
of the Evennia distribution and its unit tests should be run with all other Evennia tests using
`evennia test evennia`.
The way to do this is to only temporarily add your models to the `INSTALLED_APPS` directory when the test runs. here is an example of how to do it.
> Note that this solution, derived from this [stackexchange answer](http://stackoverflow.com/questions/502916/django-how-to-create-a-model-dynamically-just-for-testing#503435) is currently untested! Please report your findings.
```python
# a file contrib/mycontrib/tests.py
from django.conf import settings
import django
from evennia.utils.test_resources import BaseEvenniaTest
OLD_DEFAULT_SETTINGS = settings.INSTALLED_APPS
DEFAULT_SETTINGS = dict(
INSTALLED_APPS=(
'contrib.mycontrib.tests',
),
DATABASES={
"default": {
"ENGINE": "django.db.backends.sqlite3"
}
},
SILENCED_SYSTEM_CHECKS=["1_7.W001"],
)
class TestMyModel(BaseEvenniaTest):
def setUp(self):
if not settings.configured:
settings.configure(**DEFAULT_SETTINGS)
django.setup()
from django.core.management import call_command
from django.db.models import loading
loading.cache.loaded = False
call_command('syncdb', verbosity=0)
def tearDown(self):
settings.configure(**OLD_DEFAULT_SETTINGS)
django.setup()
from django.core.management import call_command
from django.db.models import loading
loading.cache.loaded = False
call_command('syncdb', verbosity=0)
# test cases below ...
def test_case(self):
# test case here
```
### A note on making the test runner faster
If you have custom models with a large number of migrations, creating the test database can take a very long time. If you don't require migrations to run for your tests, you can disable them with the
django-test-without-migrations package. To install it, simply:
```
$ pip install django-test-without-migrations
```
Then add it to your `INSTALLED_APPS` in your `server.conf.settings.py`:
```python
INSTALLED_APPS = (
# ...
'test_without_migrations',
)
```
After doing so, you can then run tests without migrations by adding the `--nomigrations` argument:
```
evennia test --settings settings.py --nomigrations .