mirror of
https://github.com/evennia/evennia.git
synced 2026-03-18 13:56:30 +01:00
Updated HTML docs
This commit is contained in:
parent
7c06220c24
commit
3aaf366163
89 changed files with 1540 additions and 1583 deletions
|
|
@ -69,118 +69,195 @@ how many tests were run and how long it took. If something went wrong you will g
|
|||
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-with-custom-settings-file">
|
||||
<h2>Running tests with custom settings file<a class="headerlink" href="#running-tests-with-custom-settings-file" title="Permalink to this headline">¶</a></h2>
|
||||
<p>If you have implemented your own tests for your game (see below) you can run them from your game dir
|
||||
<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 .
|
||||
</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>Those tests will all be run using the default settings. 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>
|
||||
<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>
|
||||
<blockquote>
|
||||
<div><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.</p>
|
||||
</div></blockquote>
|
||||
<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 a testing file, a <code class="docutils literal notranslate"><span class="pre">unittest.TestCase</span></code> class is used to test a single aspect or component in
|
||||
various ways. Each test case contains one or more <em>test methods</em> - these define the actual tests to
|
||||
run. You can name the test methods anything you want as long as the name starts with “<code class="docutils literal notranslate"><span class="pre">test_</span></code>”.
|
||||
Your <code class="docutils literal notranslate"><span class="pre">TestCase</span></code> class can also have a method <code class="docutils literal notranslate"><span class="pre">setUp()</span></code>. This is run before each test, setting up and
|
||||
storing whatever preparations the test methods need. Conversely, a <code class="docutils literal notranslate"><span class="pre">tearDown()</span></code> method can
|
||||
optionally do cleanup after each test.</p>
|
||||
<p>To test the results, you use special methods of the <code class="docutils literal notranslate"><span class="pre">TestCase</span></code> class. Many of those start with
|
||||
“<code class="docutils literal notranslate"><span class="pre">assert</span></code>”, such as <code class="docutils literal notranslate"><span class="pre">assertEqual</span></code> or <code class="docutils literal notranslate"><span class="pre">assertTrue</span></code>.</p>
|
||||
<p>Example of a <code class="docutils literal notranslate"><span class="pre">TestCase</span></code> class:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">import</span> <span class="nn">unittest</span>
|
||||
<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">mypath</span> <span class="kn">import</span> <span class="n">myfunc</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="s2">"test method. Makes sure return value is as expected."</span>
|
||||
<span class="n">expected_return</span> <span class="o">=</span> <span class="s2">"This is me being nice."</span>
|
||||
<span class="n">actual_return</span> <span class="o">=</span> <span class="n">myfunc</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="s2">"test method. Calls with a keyword argument."</span>
|
||||
<span class="n">expected_return</span> <span class="o">=</span> <span class="s2">"This is me being baaaad."</span>
|
||||
<span class="n">actual_return</span> <span class="o">=</span> <span class="n">myfunc</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="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>You might also want to read the <a class="reference external" href="https://docs.python.org/library/unittest.html">documentation for the unittest
|
||||
module</a>.</p>
|
||||
<section id="using-the-evenniatest-class">
|
||||
<h3>Using the EvenniaTest class<a class="headerlink" href="#using-the-evenniatest-class" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Evennia offers a custom TestCase, the <code class="docutils literal notranslate"><span class="pre">evennia.utils.test_resources.EvenniaTest</span></code> class. This class
|
||||
initiates a range of useful properties on themselves for testing Evennia systems. Examples are
|
||||
<code class="docutils literal notranslate"><span class="pre">.account</span></code> and <code class="docutils literal notranslate"><span class="pre">.session</span></code> representing a mock connected Account and its Session and <code class="docutils literal notranslate"><span class="pre">.char1</span></code> and
|
||||
<code class="docutils literal notranslate"><span class="pre">char2</span></code> representing Characters complete with a location in the test database. These are all useful
|
||||
when testing Evennia system requiring any of the default Evennia typeclasses as inputs. See the full
|
||||
definition of the <code class="docutils literal notranslate"><span class="pre">EvenniaTest</span></code> class in
|
||||
<a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/utils/test_resources.py">evennia/utils/test_resources.py</a>.</p>
|
||||
<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
|
||||
<a class="reference internal" href="../api/evennia.utils.test_resources.html#evennia.utils.test_resources.EvenniaCommandTestMixin.call" title="evennia.utils.test_resources.EvenniaCommandTestMixin.call"><span class="xref myst py py-meth">.call()</span></a> 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">BaseEvenniaTest</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">BaseEvenniaTest</span><span class="p">):</span>
|
||||
<span class="k">def</span> <span class="nf">test_object_search</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="c1"># char1 and char2 are both created in room1</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>
|
||||
</section>
|
||||
<section id="testing-in-game-commands">
|
||||
<h3>Testing in-game Commands<a class="headerlink" href="#testing-in-game-commands" title="Permalink to this headline">¶</a></h3>
|
||||
<p>In-game Commands are a special case. Tests for the default commands are put in
|
||||
<code class="docutils literal notranslate"><span class="pre">evennia/commands/default/tests.py</span></code>. This uses a custom <code class="docutils literal notranslate"><span class="pre">CommandTest</span></code> class that inherits from
|
||||
<code class="docutils literal notranslate"><span class="pre">evennia.utils.test_resources.EvenniaTest</span></code> described above. <code class="docutils literal notranslate"><span class="pre">CommandTest</span></code> supplies extra convenience
|
||||
functions for executing commands and check that their return values (calls of <code class="docutils literal notranslate"><span class="pre">msg()</span></code> returns
|
||||
expected values. It uses Characters and Sessions generated on the <code class="docutils literal notranslate"><span class="pre">EvenniaTest</span></code> class to call each
|
||||
class).</p>
|
||||
<p>Each command tested should have its own <code class="docutils literal notranslate"><span class="pre">TestCase</span></code> class. Inherit this class from the <code class="docutils literal notranslate"><span class="pre">CommandTest</span></code>
|
||||
class in the same module to get access to the command-specific utilities mentioned.</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">CommandTest</span>
|
||||
<span class="kn">from</span> <span class="nn">evennia.commands.default</span> <span class="kn">import</span> <span class="n">general</span>
|
||||
<span class="k">class</span> <span class="nc">TestSet</span><span class="p">(</span><span class="n">CommandTest</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">general</span><span class="o">.</span><span class="n">CmdLook</span><span class="p">(),</span> <span class="s2">"Char2"</span><span class="p">,</span> <span class="s2">"Char2(#7)"</span><span class="p">)</span>
|
||||
<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="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="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="n">general</span><span class="o">.</span><span class="n">CmdLook</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>
|
||||
<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
|
||||
<a class="reference internal" href="../api/evennia.utils.test_resources.html#evennia.utils.test_resources.EvenniaCommandTestMixin.call" title="evennia.utils.test_resources.EvenniaCommandTestMixin.call"><span class="xref myst py py-meth">read the API docs for .call()</span></a>.</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">
|
||||
<h3>Unit testing contribs with custom models<a class="headerlink" href="#unit-testing-contribs-with-custom-models" title="Permalink to this headline">¶</a></h3>
|
||||
<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
|
||||
|
|
@ -243,15 +320,8 @@ testing#503435) is currently untested! Please report your findings.</p>
|
|||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="a-note-on-adding-new-tests">
|
||||
<h3>A note on adding new tests<a class="headerlink" href="#a-note-on-adding-new-tests" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Having an extensive tests suite is very important for avoiding code degradation as Evennia is
|
||||
developed. Only a small fraction of the Evennia codebase is covered by test suites at this point.
|
||||
Writing new tests is not hard, it’s more a matter of finding the time to do so. So adding new tests
|
||||
is really an area where everyone can contribute, also with only limited Python skills.</p>
|
||||
</section>
|
||||
<section id="a-note-on-making-the-test-runner-faster">
|
||||
<h3>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></h3>
|
||||
<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>
|
||||
|
|
@ -270,152 +340,6 @@ django-test-without-migrations package. To install it, simply:</p>
|
|||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="testing-for-game-development-mini-tutorial">
|
||||
<h2>Testing for Game development (mini-tutorial)<a class="headerlink" href="#testing-for-game-development-mini-tutorial" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Unit testing can be of paramount importance to game developers. When starting with a new game, it is
|
||||
recommended to look into unit testing as soon as possible; an already huge game is much harder to
|
||||
write tests for. The benefits of testing a game aren’t different from the ones regarding library
|
||||
testing. For example it is easy to introduce bugs that affect previously working code. Testing is
|
||||
there to ensure your project behaves the way it should and continue to do so.</p>
|
||||
<p>If you have never used unit testing (with Python or another language), you might want to check the
|
||||
<a class="reference external" href="https://docs.python.org/2/library/unittest.html">official Python documentation about unit testing</a>,
|
||||
particularly the first section dedicated to a basic example.</p>
|
||||
<section id="basic-testing-using-evennia">
|
||||
<h3>Basic testing using Evennia<a class="headerlink" href="#basic-testing-using-evennia" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Evennia’s test runner can be used to launch tests in your game directory (let’s call it ‘mygame’).
|
||||
Evennia’s test runner does a few useful things beyond the normal Python unittest module:</p>
|
||||
<ul class="simple">
|
||||
<li><p>It creates and sets up an empty database, with some useful objects (accounts, characters and
|
||||
rooms, among others).</p></li>
|
||||
<li><p>It provides simple ways to test commands, which can be somewhat tricky at times, if not tested
|
||||
properly.</p></li>
|
||||
</ul>
|
||||
<p>Therefore, you should use the command-line to execute the test runner, while specifying your own
|
||||
game directories (not the one containing evennia). Go to your game directory (referred as ‘mygame’
|
||||
in this section) and execute the test runner:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evennia --settings settings.py test commands
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This command will execute Evennia’s test runner using your own settings file. It will set up a dummy
|
||||
database of your choice and look into the ‘commands’ package defined in your game directory
|
||||
(<code class="docutils literal notranslate"><span class="pre">mygame/commands</span></code> in this example) to find tests. The test module’s name should begin with ‘test’
|
||||
and contain one or more <code class="docutils literal notranslate"><span class="pre">TestCase</span></code>. A full example can be found below.</p>
|
||||
</section>
|
||||
<section id="a-simple-example">
|
||||
<h3>A simple example<a class="headerlink" href="#a-simple-example" title="Permalink to this headline">¶</a></h3>
|
||||
<p>In your game directory, go to <code class="docutils literal notranslate"><span class="pre">commands</span></code> and create a new file <code class="docutils literal notranslate"><span class="pre">tests.py</span></code> inside (it could be named
|
||||
anything starting with <code class="docutils literal notranslate"><span class="pre">test</span></code>). We will start by making a test that has nothing to do with Commands,
|
||||
just to show how unit testing works:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="c1"># mygame/commands/tests.py</span>
|
||||
|
||||
<span class="kn">import</span> <span class="nn">unittest</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">TestString</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="sd">"""Unittest for strings (just a basic example)."""</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">test_upper</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="sd">"""Test the upper() str method."""</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span><span class="s1">'foo'</span><span class="o">.</span><span class="n">upper</span><span class="p">(),</span> <span class="s1">'FOO'</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This example, inspired from the Python documentation, is used to test the ‘upper()’ method of the
|
||||
‘str’ class. Not very useful, but it should give you a basic idea of how tests are used.</p>
|
||||
<p>Let’s execute that test to see if it works.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> evennia --settings settings.py test commands
|
||||
|
||||
TESTING: Using specified settings file 'server.conf.settings'.
|
||||
|
||||
(Obs: Evennia's full test suite may not pass if the settings are very
|
||||
different from the default. Use 'test .' as arguments to run only tests
|
||||
on the game dir.)
|
||||
|
||||
Creating test database for alias 'default'...
|
||||
.
|
||||
----------------------------------------------------------------------
|
||||
Ran 1 test in 0.001s
|
||||
|
||||
OK
|
||||
Destroying test database for alias 'default'...
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>We specified the <code class="docutils literal notranslate"><span class="pre">commands</span></code> package to the evennia test command since that’s where we put our test
|
||||
file. In this case we could just as well just said <code class="docutils literal notranslate"><span class="pre">.</span></code> to search all of <code class="docutils literal notranslate"><span class="pre">mygame</span></code> for testing files.
|
||||
If we have a lot of tests it may be useful to test only a single set at a time though. We get an
|
||||
information text telling us we are using our custom settings file (instead of Evennia’s default
|
||||
file) and then the test runs. The test passes! Change the “FOO” string to something else in the test
|
||||
to see how it looks when it fails.</p>
|
||||
</section>
|
||||
<section id="testing-commands">
|
||||
<h3>Testing commands<a class="headerlink" href="#testing-commands" title="Permalink to this headline">¶</a></h3>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>This is not correct anymore.</p>
|
||||
</div>
|
||||
<p>This section will test the proper execution of the ‘abilities’ command, as described in the DELETED
|
||||
tutorial to create the ‘abilities’ command, we will need it to test it.</p>
|
||||
<p>Testing commands in Evennia is a bit more complex than the simple testing example we have seen.
|
||||
Luckily, Evennia supplies a special test class to do just that … we just need to inherit from it
|
||||
and use it properly. This class is called ‘CommandTest’ and is defined in the
|
||||
‘evennia.commands.default.tests’ package. To create a test for our ‘abilities’ command, we just
|
||||
need to create a class that inherits from ‘CommandTest’ and add methods.</p>
|
||||
<p>We could create a new test file for this but for now we just append to the <code class="docutils literal notranslate"><span class="pre">tests.py</span></code> file we
|
||||
already have in <code class="docutils literal notranslate"><span class="pre">commands</span></code> from before.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="c1"># bottom of mygame/commands/tests.py</span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">evennia.commands.default.tests</span> <span class="kn">import</span> <span class="n">CommandTest</span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">commands.command</span> <span class="kn">import</span> <span class="n">CmdAbilities</span>
|
||||
<span class="kn">from</span> <span class="nn">typeclasses.characters</span> <span class="kn">import</span> <span class="n">Character</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">TestAbilities</span><span class="p">(</span><span class="n">CommandTest</span><span class="p">):</span>
|
||||
|
||||
<span class="n">character_typeclass</span> <span class="o">=</span> <span class="n">Character</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">test_simple</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">CmdAbilities</span><span class="p">(),</span> <span class="s2">""</span><span class="p">,</span> <span class="s2">"STR: 5, AGI: 4, MAG: 2"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<ul class="simple">
|
||||
<li><p>Line 1-4: we do some importing. ‘CommandTest’ is going to be our base class for our test, so we
|
||||
need it. We also import our command (‘CmdAbilities’ in this case). Finally we import the
|
||||
‘Character’ typeclass. We need it, since ‘CommandTest’ doesn’t use ‘Character’, but
|
||||
‘DefaultCharacter’, which means the character calling the command won’t have the abilities we have
|
||||
written in the ‘Character’ typeclass.</p></li>
|
||||
<li><p>Line 6-8: that’s the body of our test. Here, a single command is tested in an entire class.
|
||||
Default commands are usually grouped by category in a single class. There is no rule, as long as
|
||||
you know where you put your tests. Note that we set the ‘character_typeclass’ class attribute to
|
||||
Character. As explained above, if you didn’t do that, the system would create a ‘DefaultCharacter’
|
||||
object, not a ‘Character’. You can try to remove line 4 and 8 to see what happens when running the
|
||||
test.</p></li>
|
||||
<li><p>Line 10-11: our unique testing method. Note its name: it should begin by ‘test_’. Apart from
|
||||
that, the method is quite simple: it’s an instance method (so it takes the ‘self’ argument) but no
|
||||
other arguments are needed. Line 11 uses the ‘call’ method, which is defined in ‘CommandTest’.
|
||||
It’s a useful method that compares a command against an expected result. It would be like comparing
|
||||
two strings with ‘assertEqual’, but the ‘call’ method does more things, including testing the
|
||||
command in a realistic way (calling its hooks in the right order, so you don’t have to worry about
|
||||
that).</p></li>
|
||||
</ul>
|
||||
<p>Line 11 can be understood as: test the ‘abilities’ command (first parameter), with no argument
|
||||
(second parameter), and check that the character using it receives his/her abilities (third
|
||||
parameter).</p>
|
||||
<p>Let’s run our new test:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> evennia --settings settings.py test commands
|
||||
[...]
|
||||
Creating test database for alias 'default'...
|
||||
..
|
||||
----------------------------------------------------------------------
|
||||
Ran 2 tests in 0.156s
|
||||
|
||||
OK
|
||||
Destroying test database for alias 'default'...
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Two tests were executed, since we have kept ‘TestString’ from last time. In case of failure, you
|
||||
will get much more information to help you fix the bug.</p>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
@ -442,23 +366,17 @@ will get much more information to help you fix the bug.</p>
|
|||
<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-with-custom-settings-file">Running tests with custom settings file</a></li>
|
||||
<li><a class="reference internal" href="#writing-new-tests">Writing new tests</a><ul>
|
||||
<li><a class="reference internal" href="#using-the-evenniatest-class">Using the EvenniaTest class</a></li>
|
||||
<li><a class="reference internal" href="#testing-in-game-commands">Testing in-game Commands</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-adding-new-tests">A note on adding new tests</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>
|
||||
<li><a class="reference internal" href="#testing-for-game-development-mini-tutorial">Testing for Game development (mini-tutorial)</a><ul>
|
||||
<li><a class="reference internal" href="#basic-testing-using-evennia">Basic testing using Evennia</a></li>
|
||||
<li><a class="reference internal" href="#a-simple-example">A simple example</a></li>
|
||||
<li><a class="reference internal" href="#testing-commands">Testing commands</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div role="note" aria-label="source link">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue