<pclass="last">You are reading an old version of the Evennia documentation. <ahref="https://www.evennia.com/docs/latest/index.html">The latest version is here</a></p>.
<h1>Unit Testing<aclass="headerlink"href="#unit-testing"title="Permalink to this headline">¶</a></h1>
<p><em>Unit testing</em> 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 <aclass="reference external"href="https://en.wikipedia.org/wiki/Unit_test">here</a>).</p>
<p>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 <em>test runner</em>. This is a program that gathers all available tests all over the Evennia source code (called <em>test suites</em>) and runs them all in one go. Errors and tracebacks are reported.</p>
<p>By default Evennia only tests itself. But you can also add your own tests to your game code and have Evennia run those for you.</p>
<sectionid="running-the-evennia-test-suite">
<h2>Running the Evennia test suite<aclass="headerlink"href="#running-the-evennia-test-suite"title="Permalink to this headline">¶</a></h2>
<p>To run the full Evennia test suite, go to your game folder and issue the command</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>evennia test evennia
</pre></div>
</div>
<p>This will run all the evennia tests using the default settings. You could also run only a subset of
all tests by specifying a subpackage of the library:</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>evennia test evennia.commands.default
</pre></div>
</div>
<p>A temporary database will be instantiated to manage the tests. If everything works out you will see
how many tests were run and how long it took. If something went wrong you will get error messages.
If you contribute to Evennia, this is a useful sanity check to see you haven’t introduced an
unexpected bug.</p>
</section>
<sectionid="running-custom-game-dir-unit-tests">
<h2>Running custom game-dir unit tests<aclass="headerlink"href="#running-custom-game-dir-unit-tests"title="Permalink to this headline">¶</a></h2>
<p>If you have implemented your own tests for your game you can run them from your game dir
with</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>evennia test --settings settings.py .
</pre></div>
</div>
<p>The period (<codeclass="docutils literal notranslate"><spanclass="pre">.</span></code>) means to run all tests found in the current directory and all subdirectories. You
could also specify, say, <codeclass="docutils literal notranslate"><spanclass="pre">typeclasses</span></code> or <codeclass="docutils literal notranslate"><spanclass="pre">world</span></code> if you wanted to just run tests in those subdirs.</p>
<p>An important thing to note is that those tests will all be run using the <em>default Evennia settings</em>.
To run the tests with your own settings file you must use the <codeclass="docutils literal notranslate"><spanclass="pre">--settings</span></code> option:</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>evennia test --settings settings.py .
</pre></div>
</div>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">--settings</span></code> option of Evennia takes a file name in the <codeclass="docutils literal notranslate"><spanclass="pre">mygame/server/conf</span></code> folder. It is
normally used to swap settings files for testing and development. In combination with <codeclass="docutils literal notranslate"><spanclass="pre">test</span></code>, it
forces Evennia to use this settings file over the default one.</p>
<p>You can also test specific things by giving their path</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>evennia test --settings settings.py world.tests.YourTest
</pre></div>
</div>
</section>
<sectionid="writing-new-unit-tests">
<h2>Writing new unit tests<aclass="headerlink"href="#writing-new-unit-tests"title="Permalink to this headline">¶</a></h2>
<p>Evennia’s test suite makes use of Django unit test system, which in turn relies on Python’s
<em>unittest</em> module.</p>
<p>To make the test runner find the tests, they must be put in a module named <codeclass="docutils literal notranslate"><spanclass="pre">test*.py</span></code> (so <codeclass="docutils literal notranslate"><spanclass="pre">test.py</span></code>,
<codeclass="docutils literal notranslate"><spanclass="pre">tests.py</span></code> etc). Such a test module will be found wherever it is in the package. It can be a good
idea to look at some of Evennia’s <codeclass="docutils literal notranslate"><spanclass="pre">tests.py</span></code> modules to see how they look.</p>
<p>Inside the module you need to put a class inheriting (at any distance) from <codeclass="docutils literal notranslate"><spanclass="pre">unittest.TestCase</span></code>. Each
method on that class that starts with <codeclass="docutils literal notranslate"><spanclass="pre">test_</span></code> will be run separately as a unit test. There
are two special, optional methods <codeclass="docutils literal notranslate"><spanclass="pre">setUp</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">tearDown</span></code> that will (if you define them) run before
<em>every</em> test. This can be useful for setting up and deleting things.</p>
<p>To actually test things, you use special <codeclass="docutils literal notranslate"><spanclass="pre">assert...</span></code> methods on the class. Most common on is
<codeclass="docutils literal notranslate"><spanclass="pre">assertEqual</span></code>, which makes sure a result is what you expect it to be.</p>
<p>Here’s an example of the principle. Let’s assume you put this in <codeclass="docutils literal notranslate"><spanclass="pre">mygame/world/tests.py</span></code>
and want to test a function in <codeclass="docutils literal notranslate"><spanclass="pre">mygame/world/myfunctions.py</span></code></p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in a module tests.py somewhere i your game dir</span>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>evennia test --settings settings.py .
</pre></div>
</div>
<p>to run the entire test module</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>evennia test --settings settings.py world.tests
</pre></div>
</div>
<p>or a specific class:</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>evennia test --settings settings.py world.tests.TestObj
</pre></div>
</div>
<p>You can also run a specific test:</p>
<divclass="highlight-none notranslate"><divclass="highlight"><pre><span></span>evennia test --settings settings.py world.tests.TestObj.test_alternative_call
</pre></div>
</div>
<p>You might also want to read the <aclass="reference external"href="https://docs.python.org/library/unittest.html">Python documentation for the unittest module</a>.</p>
<sectionid="using-the-evennia-testing-classes">
<h3>Using the Evennia testing classes<aclass="headerlink"href="#using-the-evennia-testing-classes"title="Permalink to this headline">¶</a></h3>
<p>Evennia offers many custom testing classes that helps with testing Evennia features.
They are all found in <aclass="reference internal"href="../api/evennia.utils.test_resources.html#evennia-utils-test-resources"><spanclass="std std-ref">evennia.utils.test_resources</span></a>. Note that
these classes implement the <codeclass="docutils literal notranslate"><spanclass="pre">setUp</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">tearDown</span></code> already, so if you want to add stuff in them
yourself you should remember to use e.g. <codeclass="docutils literal notranslate"><spanclass="pre">super().setUp()</span></code> in your code.</p>
<sectionid="classes-for-testing-your-game-dir">
<h4>Classes for testing your game dir<aclass="headerlink"href="#classes-for-testing-your-game-dir"title="Permalink to this headline">¶</a></h4>
<p>These all use whatever setting you pass to them and works well for testing code in your game dir.</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">EvenniaTest</span></code> - this sets up a full object environment for your test. All the created entities
can be accesses as properties on the class:</p>
<ul>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">.account</span></code> - A fake <aclass="reference internal"href="../api/evennia.accounts.accounts.html#evennia.accounts.accounts.DefaultAccount"title="evennia.accounts.accounts.DefaultAccount"><spanclass="xref myst py py-class">Account</span></a> named “TestAccount”.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">.account2</span></code> - Another account named “TestAccount2”</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">char1</span></code> - A <aclass="reference internal"href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultCharacter"title="evennia.objects.objects.DefaultCharacter"><spanclass="xref myst py py-class">Character</span></a> linked to <codeclass="docutils literal notranslate"><spanclass="pre">.account</span></code>, named <codeclass="docutils literal notranslate"><spanclass="pre">Char</span></code>.
This has ‘Developer’ permissions but is not a superuser.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">.char2</span></code> - Another character linked to <codeclass="docutils literal notranslate"><spanclass="pre">account</span></code>, named <codeclass="docutils literal notranslate"><spanclass="pre">Char2</span></code>. This has base permissions (player).</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">.obj1</span></code> - A regular <aclass="reference internal"href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultObject"title="evennia.objects.objects.DefaultObject"><spanclass="xref myst py py-class">Object</span></a> named “Obj”.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">.obj2</span></code> - Another object named “Obj2”.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">.room1</span></code> - A <aclass="reference internal"href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultRoom"title="evennia.objects.objects.DefaultRoom"><spanclass="xref myst py py-class">Room</span></a> named “Room”. Both characters and both
objects are located inside this room. It has a description of “room_desc”.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">.room2</span></code> - Another room named “Room2”. It is empty and has no set description.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">.exit</span></code> - An exit named “out” that leads from <codeclass="docutils literal notranslate"><spanclass="pre">.room1</span></code> to <codeclass="docutils literal notranslate"><spanclass="pre">.room2</span></code>.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">.script</span></code> - A <aclass="reference internal"href="../api/evennia.scripts.scripts.html#evennia.scripts.scripts.DefaultScript"title="evennia.scripts.scripts.DefaultScript"><spanclass="xref myst py py-class">Script</span></a> named “Script”. It’s an inert script
without a timing component.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">.session</span></code> - A fake <aclass="reference internal"href="../api/evennia.server.serversession.html#evennia.server.serversession.ServerSession"title="evennia.server.serversession.ServerSession"><spanclass="xref myst py py-class">Session</span></a> that mimics a player
connecting to the game. It is used by <codeclass="docutils literal notranslate"><spanclass="pre">.account1</span></code> and has a sessid of 1.</p></li>
</ul>
</li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">EvenniaCommandTest</span></code> - has the same environment like <codeclass="docutils literal notranslate"><spanclass="pre">EvenniaTest</span></code> but also adds a special
<aclass="reference internal"href="../api/evennia.utils.test_resources.html#evennia.utils.test_resources.EvenniaCommandTestMixin.call"title="evennia.utils.test_resources.EvenniaCommandTestMixin.call"><spanclass="xref myst py py-meth">.call()</span></a> method specifically for
testing Evennia <aclass="reference internal"href="../Components/Commands.html"><spanclass="doc std std-doc">Commands</span></a>. It allows you to compare what the command <em>actually</em>
returns to the player with what you expect. Read the <codeclass="docutils literal notranslate"><spanclass="pre">call</span></code> api doc for more info.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">EvenniaTestCase</span></code> - This is identical to the regular Python <codeclass="docutils literal notranslate"><spanclass="pre">TestCase</span></code> class, it’s
just there for naming symmetry with <codeclass="docutils literal notranslate"><spanclass="pre">BaseEvenniaTestCase</span></code> below.</p></li>
</ul>
<p>Here’s an example of using <codeclass="docutils literal notranslate"><spanclass="pre">EvenniaTest</span></code></p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># in a test module</span>
<spanclass="w"></span><spanclass="sd">"""Remember that the testing class creates char1 and char2 inside room1 ..."""</span>
<p>When using <codeclass="docutils literal notranslate"><spanclass="pre">.call</span></code>, you don’t need to specify the entire string; you can just give the beginning
of it and if it matches, that’s enough. Use <codeclass="docutils literal notranslate"><spanclass="pre">\n</span></code> to denote line breaks and (this is a special for
the <codeclass="docutils literal notranslate"><spanclass="pre">.call</span></code> helper), <codeclass="docutils literal notranslate"><spanclass="pre">||</span></code> to indicate multiple uses of <codeclass="docutils literal notranslate"><spanclass="pre">.msg()</span></code> in the Command. The <codeclass="docutils literal notranslate"><spanclass="pre">.call</span></code> helper
has a lot of arguments for mimicing different ways of calling a Command, so make sure to
<aclass="reference internal"href="../api/evennia.utils.test_resources.html#evennia.utils.test_resources.EvenniaCommandTestMixin.call"title="evennia.utils.test_resources.EvenniaCommandTestMixin.call"><spanclass="xref myst py py-meth">read the API docs for .call()</span></a>.</p>
</section>
<sectionid="classes-for-testing-evennia-core">
<h4>Classes for testing Evennia core<aclass="headerlink"href="#classes-for-testing-evennia-core"title="Permalink to this headline">¶</a></h4>
<p>These are used for testing Evennia itself. They provide the same resources as the classes
above but enforce Evennias default settings found in <codeclass="docutils literal notranslate"><spanclass="pre">evennia/settings_default.py</span></code>, ignoring
any settings changes in your game dir.</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">BaseEvenniaTest</span></code> - all the default objects above but with enforced default settings</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">BaseEvenniaCommandTest</span></code> - for testing Commands, but with enforced default settings</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">BaseEvenniaTestCase</span></code> - no default objects, only enforced default settings</p></li>
</ul>
<p>There are also two special ‘mixin’ classes. These are uses in the classes above, but may also
be useful if you want to mix your own testing classes:</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">EvenniaTestMixin</span></code> - A class mixin that creates all test environment objects.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">EvenniaCommandMixin</span></code> - A class mixin that adds the <codeclass="docutils literal notranslate"><spanclass="pre">.call()</span></code> Command-tester helper.</p></li>
</ul>
<p>If you want to help out writing unittests for Evennia, take a look at Evennia’s <aclass="reference external"href="https://coveralls.io/github/evennia/evennia">coveralls.io
page</a>. There you see which modules have any form of
test coverage and which does not. All help is appreciated!</p>
<h3>Unit testing contribs with custom models<aclass="headerlink"href="#unit-testing-contribs-with-custom-models"title="Permalink to this headline">¶</a></h3>
<p>A special case is if you were to create a contribution to go to the <codeclass="docutils literal notranslate"><spanclass="pre">evennia/contrib</span></code> folder that
uses its <aclass="reference internal"href="../Concepts/Models.html"><spanclass="doc std std-doc">own database models</span></a>. The problem with this is that Evennia (and Django) will
only recognize models in <codeclass="docutils literal notranslate"><spanclass="pre">settings.INSTALLED_APPS</span></code>. 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 <codeclass="docutils literal notranslate"><spanclass="pre">settings_default.py</span></code> 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
<p>The way to do this is to only temporarily add your models to the <codeclass="docutils literal notranslate"><spanclass="pre">INSTALLED_APPS</span></code> directory when the test runs. here is an example of how to do it.</p>
<blockquote>
<div><p>Note that this solution, derived from this <aclass="reference external"href="http://stackoverflow.com/questions/502916/django-how-to-create-a-model-dynamically-just-for-testing#503435">stackexchange answer</a> is currently untested! Please report your findings.</p>
</div></blockquote>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># a file contrib/mycontrib/tests.py</span>
<h3>A note on making the test runner faster<aclass="headerlink"href="#a-note-on-making-the-test-runner-faster"title="Permalink to this headline">¶</a></h3>
<p>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:</p>
<p>Then add it to your <codeclass="docutils literal notranslate"><spanclass="pre">INSTALLED_APPS</span></code> in your <codeclass="docutils literal notranslate"><spanclass="pre">server.conf.settings.py</span></code>:</p>
<p>After doing so, you can then run tests without migrations by adding the <codeclass="docutils literal notranslate"><spanclass="pre">--nomigrations</span></code> argument:</p>
<pclass="last">You are reading an old version of the Evennia documentation. <ahref="https://www.evennia.com/docs/latest/index.html">The latest version is here</a></p>.