mirror of
https://github.com/evennia/evennia.git
synced 2026-03-18 13:56:30 +01:00
450 lines
No EOL
39 KiB
HTML
450 lines
No EOL
39 KiB
HTML
|
||
<!DOCTYPE html>
|
||
|
||
<html>
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||
|
||
<title>Unit Testing — Evennia 1.0-dev documentation</title>
|
||
<link rel="stylesheet" href="../_static/nature.css" type="text/css" />
|
||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
||
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
|
||
<script src="../_static/jquery.js"></script>
|
||
<script src="../_static/underscore.js"></script>
|
||
<script src="../_static/doctools.js"></script>
|
||
<script src="../_static/language_data.js"></script>
|
||
<link rel="shortcut icon" href="../_static/favicon.ico"/>
|
||
<link rel="index" title="Index" href="../genindex.html" />
|
||
<link rel="search" title="Search" href="../search.html" />
|
||
<link rel="next" title="Profiling" href="Profiling.html" />
|
||
<link rel="prev" title="Debugging" href="Debugging.html" />
|
||
</head><body>
|
||
<div class="related" role="navigation" aria-label="related navigation">
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li class="right" style="margin-right: 10px">
|
||
<a href="../genindex.html" title="General Index"
|
||
accesskey="I">index</a></li>
|
||
<li class="right" >
|
||
<a href="../py-modindex.html" title="Python Module Index"
|
||
>modules</a> |</li>
|
||
<li class="right" >
|
||
<a href="Profiling.html" title="Profiling"
|
||
accesskey="N">next</a> |</li>
|
||
<li class="right" >
|
||
<a href="Debugging.html" title="Debugging"
|
||
accesskey="P">previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="Coding-Overview.html" accesskey="U">Coding and development help</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Unit Testing</a></li>
|
||
</ul>
|
||
<div class="develop">develop branch</div>
|
||
</div>
|
||
|
||
<div class="document">
|
||
|
||
<div class="documentwrapper">
|
||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||
<div class="sphinxsidebarwrapper">
|
||
<p class="logo"><a href="../index.html">
|
||
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
|
||
</a></p>
|
||
<div id="searchbox" style="display: none" role="search">
|
||
<h3 id="searchlabel">Quick search</h3>
|
||
<div class="searchformwrapper">
|
||
<form class="search" action="../search.html" method="get">
|
||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||
<input type="submit" value="Go" />
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<script>$('#searchbox').show(0);</script>
|
||
<h3><a href="../index.html">Table of Contents</a></h3>
|
||
<ul>
|
||
<li><a class="reference internal" href="#">Unit Testing</a><ul>
|
||
<li><a class="reference internal" href="#running-the-evennia-test-suite">Running the Evennia test suite</a></li>
|
||
<li><a class="reference internal" href="#running-tests-for-your-game-dir">Running tests for your game dir</a></li>
|
||
<li><a class="reference internal" href="#writing-new-tests">Writing new tests</a></li>
|
||
<li><a class="reference internal" href="#using-the-evennia-testing-classes">Using the Evennia testing classes</a><ul>
|
||
<li><a class="reference internal" href="#classes-for-testing-your-game-dir">Classes for testing your game dir</a></li>
|
||
<li><a class="reference internal" href="#classes-for-testing-evennia-core">Classes for testing Evennia core</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#unit-testing-contribs-with-custom-models">Unit testing contribs with custom models</a></li>
|
||
<li><a class="reference internal" href="#a-note-on-making-the-test-runner-faster">A note on making the test runner faster</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<h4>Previous topic</h4>
|
||
<p class="topless"><a href="Debugging.html"
|
||
title="previous chapter">Debugging</a></p>
|
||
<h4>Next topic</h4>
|
||
<p class="topless"><a href="Profiling.html"
|
||
title="next chapter">Profiling</a></p>
|
||
<div role="note" aria-label="source link">
|
||
<!--h3>This Page</h3-->
|
||
<ul class="this-page-menu">
|
||
<li><a href="../_sources/Coding/Unit-Testing.md.txt"
|
||
rel="nofollow">Show Page Source</a></li>
|
||
</ul>
|
||
</div><h3>Links</h3>
|
||
<ul>
|
||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
|
||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||
<li>
|
||
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
|
||
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
|
||
<a href="https://evennia.blogspot.com/">Blog</a>
|
||
</li>
|
||
</ul>
|
||
<h3>Versions</h3>
|
||
<ul>
|
||
<li><a href="Unit-Testing.html">1.0-dev (develop branch)</a></li>
|
||
<ul>
|
||
<li><a href="../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||
|
||
</ul>
|
||
|
||
</div>
|
||
</div>
|
||
<div class="bodywrapper">
|
||
<div class="body" role="main">
|
||
|
||
<section class="tex2jax_ignore mathjax_ignore" id="unit-testing">
|
||
<h1>Unit Testing<a class="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 <a class="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>
|
||
<section id="running-the-evennia-test-suite">
|
||
<h2>Running the Evennia test suite<a class="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>
|
||
<div class="highlight-none notranslate"><div class="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>
|
||
<div class="highlight-none notranslate"><div class="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>
|
||
<section id="running-tests-for-your-game-dir">
|
||
<h2>Running tests for your game dir<a class="headerlink" href="#running-tests-for-your-game-dir" 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>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evennia test --settings settings.py .
|
||
</pre></div>
|
||
</div>
|
||
<p>The period (<code class="docutils literal notranslate"><span class="pre">.</span></code>) means to run all tests found in the current directory and all subdirectories. You
|
||
could also specify, say, <code class="docutils literal notranslate"><span class="pre">typeclasses</span></code> or <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">--settings</span></code> option:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evennia test --settings settings.py .
|
||
</pre></div>
|
||
</div>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">--settings</span></code> option of Evennia takes a file name in the <code class="docutils literal notranslate"><span class="pre">mygame/server/conf</span></code> folder. It is
|
||
normally used to swap settings files for testing and development. In combination with <code class="docutils literal notranslate"><span class="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>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evennia test --settings settings.py .world.tests.YourTest
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="writing-new-tests">
|
||
<h2>Writing new tests<a class="headerlink" href="#writing-new-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 <code class="docutils literal notranslate"><span class="pre">test*.py</span></code> (so <code class="docutils literal notranslate"><span class="pre">test.py</span></code>,
|
||
<code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">unittest.TestCase</span></code>. Each
|
||
method on that class that starts with <code class="docutils literal notranslate"><span class="pre">test_</span></code> will be run separately as a unit test. There
|
||
are two special, optional methods <code class="docutils literal notranslate"><span class="pre">setUp</span></code> and <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">assert...</span></code> methods on the class. Most common on is
|
||
<code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">mygame/world/tests.py</span></code>
|
||
and want to test a function in <code class="docutils literal notranslate"><span class="pre">mygame/world/myfunctions.py</span></code></p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="c1"># in a module tests.py somewhere i your game dir</span>
|
||
<span class="kn">import</span> <span class="nn">unittest</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">create_object</span>
|
||
<span class="c1"># the function we want to test</span>
|
||
<span class="kn">from</span> <span class="nn">.myfunctions</span> <span class="kn">import</span> <span class="n">myfunc</span>
|
||
|
||
|
||
<span class="k">class</span> <span class="nc">TestObj</span><span class="p">(</span><span class="n">unittest</span><span class="o">.</span><span class="n">TestCase</span><span class="p">):</span>
|
||
<span class="s2">"This tests a function myfunc."</span>
|
||
|
||
<span class="k">def</span> <span class="nf">setUp</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="sd">"""done before every of the test_ * methods below"""</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">obj</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="s2">"mytestobject"</span><span class="p">)</span>
|
||
|
||
<span class="k">def</span> <span class="nf">tearDown</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="sd">"""done after every test_* method below """</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
|
||
|
||
<span class="k">def</span> <span class="nf">test_return_value</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="sd">"""test method. Makes sure return value is as expected."""</span>
|
||
<span class="n">actual_return</span> <span class="o">=</span> <span class="n">myfunc</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="p">)</span>
|
||
<span class="n">expected_return</span> <span class="o">=</span> <span class="s2">"This is the good object 'mytestobject'."</span>
|
||
<span class="c1"># test</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">expected_return</span><span class="p">,</span> <span class="n">actual_return</span><span class="p">)</span>
|
||
<span class="k">def</span> <span class="nf">test_alternative_call</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="sd">"""test method. Calls with a keyword argument."""</span>
|
||
<span class="n">actual_return</span> <span class="o">=</span> <span class="n">myfunc</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="p">,</span> <span class="n">bad</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||
<span class="n">expected_return</span> <span class="o">=</span> <span class="s2">"This is the baaad object 'mytestobject'."</span>
|
||
<span class="c1"># test</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="n">expected_return</span><span class="p">,</span> <span class="n">actual_return</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>To test this, run</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evennia test --settings settings.py .
|
||
</pre></div>
|
||
</div>
|
||
<p>to run the entire test module</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evennia test --settings setings.py .world.tests
|
||
</pre></div>
|
||
</div>
|
||
<p>or a specific class:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evennia test --settings settings.py .world.tests.TestObj
|
||
</pre></div>
|
||
</div>
|
||
<p>You can also run a specific test:</p>
|
||
<div class="highlight-none notranslate"><div class="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 <a class="reference external" href="https://docs.python.org/library/unittest.html">Python documentation for the unittest module</a>.</p>
|
||
</section>
|
||
<section id="using-the-evennia-testing-classes">
|
||
<h2>Using the Evennia testing classes<a class="headerlink" href="#using-the-evennia-testing-classes" title="Permalink to this headline">¶</a></h2>
|
||
<p>Evennia offers many custom testing classes that helps with testing Evennia features.
|
||
They are all found in <a class="reference internal" href="../api/evennia.utils.test_resources.html#evennia-utils-test-resources"><span class="std std-ref">evennia.utils.test_resources</span></a>. Note that
|
||
these classes implement the <code class="docutils literal notranslate"><span class="pre">setUp</span></code> and <code class="docutils literal notranslate"><span class="pre">tearDown</span></code> already, so if you want to add stuff in them
|
||
yourself you should remember to use e.g. <code class="docutils literal notranslate"><span class="pre">super().setUp()</span></code> in your code.</p>
|
||
<section id="classes-for-testing-your-game-dir">
|
||
<h3>Classes for testing your game dir<a class="headerlink" href="#classes-for-testing-your-game-dir" title="Permalink to this headline">¶</a></h3>
|
||
<p>These all use whatever setting you pass to them and works well for testing code in your game dir.</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="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><code class="docutils literal notranslate"><span class="pre">.account</span></code> - A fake <a class="reference internal" href="../api/evennia.accounts.accounts.html#evennia.accounts.accounts.DefaultAccount" title="evennia.accounts.accounts.DefaultAccount"><span class="xref myst py py-class">Account</span></a> named “TestAccount”.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">.account2</span></code> - Another account named “TestAccount2”</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">char1</span></code> - A <a class="reference internal" href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultCharacter" title="evennia.objects.objects.DefaultCharacter"><span class="xref myst py py-class">Character</span></a> linked to <code class="docutils literal notranslate"><span class="pre">.account</span></code>, named <code class="docutils literal notranslate"><span class="pre">Char</span></code>.
|
||
This has ‘Developer’ permissions but is not a superuser.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">.char2</span></code> - Another character linked to <code class="docutils literal notranslate"><span class="pre">account</span></code>, named <code class="docutils literal notranslate"><span class="pre">Char2</span></code>. This has base permissions (player).</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">.obj1</span></code> - A regular <a class="reference internal" href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultObject" title="evennia.objects.objects.DefaultObject"><span class="xref myst py py-class">Object</span></a> named “Obj”.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">.obj2</span></code> - Another object named “Obj2”.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">.room1</span></code> - A <a class="reference internal" href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultRoom" title="evennia.objects.objects.DefaultRoom"><span class="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><code class="docutils literal notranslate"><span class="pre">.room2</span></code> - Another room named “Room2”. It is empty and has no set description.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">.exit</span></code> - An exit named “out” that leads from <code class="docutils literal notranslate"><span class="pre">.room1</span></code> to <code class="docutils literal notranslate"><span class="pre">.room2</span></code>.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">.script</span></code> - A <a class="reference internal" href="../api/evennia.scripts.scripts.html#evennia.scripts.scripts.DefaultScript" title="evennia.scripts.scripts.DefaultScript"><span class="xref myst py py-class">Script</span></a> named “Script”. It’s an inert script
|
||
without a timing component.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">.session</span></code> - A fake <a class="reference internal" href="../api/evennia.server.serversession.html#evennia.server.serversession.ServerSession" title="evennia.server.serversession.ServerSession"><span class="xref myst py py-class">Session</span></a> that mimics a player
|
||
connecting to the game. It is used by <code class="docutils literal notranslate"><span class="pre">.account1</span></code> and has a sessid of 1.</p></li>
|
||
</ul>
|
||
</li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">EvenniaCommandTest</span></code> - has the same environment like <code class="docutils literal notranslate"><span class="pre">EvenniaTest</span></code> but also adds a special
|
||
<span class="xref myst">.call()</span> method specifically for
|
||
testing Evennia <a class="reference internal" href="../Components/Commands.html"><span class="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 <code class="docutils literal notranslate"><span class="pre">call</span></code> api doc for more info.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">EvenniaTestCase</span></code> - This is identical to the regular Python <code class="docutils literal notranslate"><span class="pre">TestCase</span></code> class, it’s
|
||
just there for naming symmetry with <code class="docutils literal notranslate"><span class="pre">BaseEvenniaTestCase</span></code> below.</p></li>
|
||
</ul>
|
||
<p>Here’s an example of using <code class="docutils literal notranslate"><span class="pre">EvenniaTest</span></code></p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in a test module</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">evennia.utils.test_resources</span> <span class="kn">import</span> <span class="n">EvenniaTest</span>
|
||
|
||
<span class="k">class</span> <span class="nc">TestObject</span><span class="p">(</span><span class="n">EvenniaTest</span><span class="p">):</span>
|
||
<span class="sd">"""Remember that the testing class creates char1 and char2 inside room1 ..."""</span>
|
||
<span class="k">def</span> <span class="nf">test_object_search_character</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="sd">"""Check that char1 can search for char2 by name"""</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">char1</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">char2</span><span class="o">.</span><span class="n">key</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">char2</span><span class="p">)</span>
|
||
|
||
<span class="k">def</span> <span class="nf">test_location_search</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="sd">"""Check so that char1 can find the current location by name"""</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">char1</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">char1</span><span class="o">.</span><span class="n">location</span><span class="o">.</span><span class="n">key</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">char1</span><span class="o">.</span><span class="n">location</span><span class="p">)</span>
|
||
<span class="c1"># ...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This example tests a custom command.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia.commands.default.tests</span> <span class="kn">import</span> <span class="n">EvenniaCommandTest</span>
|
||
<span class="kn">from</span> <span class="nn">commands</span> <span class="kn">import</span> <span class="n">command</span> <span class="k">as</span> <span class="n">mycommand</span>
|
||
|
||
|
||
<span class="k">class</span> <span class="nc">TestSet</span><span class="p">(</span><span class="n">EvenniaCommandTest</span><span class="p">):</span>
|
||
<span class="s2">"tests the look command by simple call, using Char2 as a target"</span>
|
||
|
||
<span class="k">def</span> <span class="nf">test_mycmd_char</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="n">mycommand</span><span class="o">.</span><span class="n">CmdMyLook</span><span class="p">(),</span> <span class="s2">"Char2"</span><span class="p">,</span> <span class="s2">"Char2(#7)"</span><span class="p">)</span>
|
||
|
||
<span class="k">def</span> <span class="nf">test_mycmd_room</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="s2">"tests the look command by simple call, with target as room"</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="n">mycommand</span><span class="o">.</span><span class="n">CmdMyLook</span><span class="p">(),</span> <span class="s2">"Room"</span><span class="p">,</span>
|
||
<span class="s2">"Room(#1)</span><span class="se">\n</span><span class="s2">room_desc</span><span class="se">\n</span><span class="s2">Exits: out(#3)</span><span class="se">\n</span><span class="s2">"</span>
|
||
<span class="s2">"You see: Obj(#4), Obj2(#5), Char2(#7)"</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>When using <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="pre">\n</span></code> to denote line breaks and (this is a special for
|
||
the <code class="docutils literal notranslate"><span class="pre">.call</span></code> helper), <code class="docutils literal notranslate"><span class="pre">||</span></code> to indicate multiple uses of <code class="docutils literal notranslate"><span class="pre">.msg()</span></code> in the Command. The <code class="docutils literal notranslate"><span class="pre">.call</span></code> helper
|
||
has a lot of arguments for mimicing different ways of calling a Command, so make sure to
|
||
<span class="xref myst">read the API docs for .call()</span>.</p>
|
||
</section>
|
||
<section id="classes-for-testing-evennia-core">
|
||
<h3>Classes for testing Evennia core<a class="headerlink" href="#classes-for-testing-evennia-core" title="Permalink to this headline">¶</a></h3>
|
||
<p>These are used for testing Evennia itself. They provide the same resources as the classes
|
||
above but enforce Evennias default settings found in <code class="docutils literal notranslate"><span class="pre">evennia/settings_default.py</span></code>, ignoring
|
||
any settings changes in your game dir.</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">BaseEvenniaTest</span></code> - all the default objects above but with enforced default settings</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">BaseEvenniaCommandTest</span></code> - for testing Commands, but with enforced default settings</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="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>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">EvenniaTestMixin</span></code> - A class mixin that creates all test environment objects.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">EvenniaCommandMixin</span></code> - A class mixin that adds the <code class="docutils literal notranslate"><span class="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 <a class="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>
|
||
</section>
|
||
</section>
|
||
<section id="unit-testing-contribs-with-custom-models">
|
||
<h2>Unit testing contribs with custom models<a class="headerlink" href="#unit-testing-contribs-with-custom-models" title="Permalink to this headline">¶</a></h2>
|
||
<p>A special case is if you were to create a contribution to go to the <code class="docutils literal notranslate"><span class="pre">evennia/contrib</span></code> folder that
|
||
uses its <a class="reference internal" href="../Concepts/New-Models.html"><span class="doc std std-doc">own database models</span></a>. The problem with this is that Evennia (and Django) will
|
||
only recognize models in <code class="docutils literal notranslate"><span class="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 <code class="docutils literal notranslate"><span class="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
|
||
<code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="pre">test</span> <span class="pre">evennia</span></code>.</p>
|
||
<p>The way to do this is to only temporarily add your models to the <code class="docutils literal notranslate"><span class="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 [stackexchange
|
||
answer](<a class="reference external" href="http://stackoverflow.com/questions/502916/django-how-to-create-a-model-dynamically-just-for-">http://stackoverflow.com/questions/502916/django-how-to-create-a-model-dynamically-just-for-</a>
|
||
testing#503435) is currently untested! Please report your findings.</p>
|
||
</div></blockquote>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># a file contrib/mycontrib/tests.py</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
|
||
<span class="kn">import</span> <span class="nn">django</span>
|
||
<span class="kn">from</span> <span class="nn">evennia.utils.test_resources</span> <span class="kn">import</span> <span class="n">BaseEvenniaTest</span>
|
||
|
||
<span class="n">OLD_DEFAULT_SETTINGS</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">INSTALLED_APPS</span>
|
||
<span class="n">DEFAULT_SETTINGS</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span>
|
||
<span class="n">INSTALLED_APPS</span><span class="o">=</span><span class="p">(</span>
|
||
<span class="s1">'contrib.mycontrib.tests'</span><span class="p">,</span>
|
||
<span class="p">),</span>
|
||
<span class="n">DATABASES</span><span class="o">=</span><span class="p">{</span>
|
||
<span class="s2">"default"</span><span class="p">:</span> <span class="p">{</span>
|
||
<span class="s2">"ENGINE"</span><span class="p">:</span> <span class="s2">"django.db.backends.sqlite3"</span>
|
||
<span class="p">}</span>
|
||
<span class="p">},</span>
|
||
<span class="n">SILENCED_SYSTEM_CHECKS</span><span class="o">=</span><span class="p">[</span><span class="s2">"1_7.W001"</span><span class="p">],</span>
|
||
<span class="p">)</span>
|
||
|
||
|
||
<span class="k">class</span> <span class="nc">TestMyModel</span><span class="p">(</span><span class="n">BaseEvenniaTest</span><span class="p">):</span>
|
||
<span class="k">def</span> <span class="nf">setUp</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="n">settings</span><span class="o">.</span><span class="n">configured</span><span class="p">:</span>
|
||
<span class="n">settings</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span><span class="o">**</span><span class="n">DEFAULT_SETTINGS</span><span class="p">)</span>
|
||
<span class="n">django</span><span class="o">.</span><span class="n">setup</span><span class="p">()</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">django.core.management</span> <span class="kn">import</span> <span class="n">call_command</span>
|
||
<span class="kn">from</span> <span class="nn">django.db.models</span> <span class="kn">import</span> <span class="n">loading</span>
|
||
<span class="n">loading</span><span class="o">.</span><span class="n">cache</span><span class="o">.</span><span class="n">loaded</span> <span class="o">=</span> <span class="kc">False</span>
|
||
<span class="n">call_command</span><span class="p">(</span><span class="s1">'syncdb'</span><span class="p">,</span> <span class="n">verbosity</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
|
||
|
||
<span class="k">def</span> <span class="nf">tearDown</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="n">settings</span><span class="o">.</span><span class="n">configure</span><span class="p">(</span><span class="o">**</span><span class="n">OLD_DEFAULT_SETTINGS</span><span class="p">)</span>
|
||
<span class="n">django</span><span class="o">.</span><span class="n">setup</span><span class="p">()</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">django.core.management</span> <span class="kn">import</span> <span class="n">call_command</span>
|
||
<span class="kn">from</span> <span class="nn">django.db.models</span> <span class="kn">import</span> <span class="n">loading</span>
|
||
<span class="n">loading</span><span class="o">.</span><span class="n">cache</span><span class="o">.</span><span class="n">loaded</span> <span class="o">=</span> <span class="kc">False</span>
|
||
<span class="n">call_command</span><span class="p">(</span><span class="s1">'syncdb'</span><span class="p">,</span> <span class="n">verbosity</span><span class="o">=</span><span class="mi">0</span><span class="p">)</span>
|
||
|
||
<span class="c1"># test cases below ...</span>
|
||
|
||
<span class="k">def</span> <span class="nf">test_case</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="c1"># test case here</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="a-note-on-making-the-test-runner-faster">
|
||
<h2>A note on making the test runner faster<a class="headerlink" href="#a-note-on-making-the-test-runner-faster" title="Permalink to this headline">¶</a></h2>
|
||
<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>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>$ pip install django-test-without-migrations
|
||
</pre></div>
|
||
</div>
|
||
<p>Then add it to your <code class="docutils literal notranslate"><span class="pre">INSTALLED_APPS</span></code> in your <code class="docutils literal notranslate"><span class="pre">server.conf.settings.py</span></code>:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">INSTALLED_APPS</span> <span class="o">=</span> <span class="p">(</span>
|
||
<span class="c1"># ...</span>
|
||
<span class="s1">'test_without_migrations'</span><span class="p">,</span>
|
||
<span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>After doing so, you can then run tests without migrations by adding the <code class="docutils literal notranslate"><span class="pre">--nomigrations</span></code> argument:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">evennia</span> <span class="n">test</span> <span class="o">--</span><span class="n">settings</span> <span class="n">settings</span><span class="o">.</span><span class="n">py</span> <span class="o">--</span><span class="n">nomigrations</span> <span class="o">.</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
</section>
|
||
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
<div class="related" role="navigation" aria-label="related navigation">
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li class="right" style="margin-right: 10px">
|
||
<a href="../genindex.html" title="General Index"
|
||
>index</a></li>
|
||
<li class="right" >
|
||
<a href="../py-modindex.html" title="Python Module Index"
|
||
>modules</a> |</li>
|
||
<li class="right" >
|
||
<a href="Profiling.html" title="Profiling"
|
||
>next</a> |</li>
|
||
<li class="right" >
|
||
<a href="Debugging.html" title="Debugging"
|
||
>previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="Coding-Overview.html" >Coding and development help</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Unit Testing</a></li>
|
||
</ul>
|
||
<div class="develop">develop branch</div>
|
||
</div>
|
||
<div class="footer" role="contentinfo">
|
||
© Copyright 2022, The Evennia developer community.
|
||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||
</div>
|
||
</body>
|
||
</html> |