mirror of
https://github.com/evennia/evennia.git
synced 2026-03-19 06:16:31 +01:00
435 lines
No EOL
32 KiB
HTML
435 lines
No EOL
32 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>1. Code structure and Utilities — Evennia 1.0 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="2. Rules and dice rolling" href="Beginner-Tutorial-Rules.html" />
|
||
<link rel="prev" title="Part 3: How we get there (example game)" href="Beginner-Tutorial-Part3-Overview.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="Beginner-Tutorial-Rules.html" title="2. Rules and dice rolling"
|
||
accesskey="N">next</a> |</li>
|
||
<li class="right" >
|
||
<a href="Beginner-Tutorial-Part3-Overview.html" title="Part 3: How we get there (example game)"
|
||
accesskey="P">previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Overview.html" >Beginner Tutorial</a> »</li>
|
||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Overview.html" accesskey="U">Part 3: How we get there (example game)</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">1. </span>Code structure and Utilities</a></li>
|
||
</ul>
|
||
</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="#">1. Code structure and Utilities</a><ul>
|
||
<li><a class="reference internal" href="#folder-structure">1.1. Folder structure</a></li>
|
||
<li><a class="reference internal" href="#enums">1.2. Enums</a></li>
|
||
<li><a class="reference internal" href="#utility-module">1.3. Utility module</a></li>
|
||
<li><a class="reference internal" href="#testing">1.4. Testing</a><ul>
|
||
<li><a class="reference internal" href="#running-your-test">1.4.1. Running your test</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#summary">1.5. Summary</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<h4>Previous topic</h4>
|
||
<p class="topless"><a href="Beginner-Tutorial-Part3-Overview.html"
|
||
title="previous chapter">Part 3: How we get there (example game)</a></p>
|
||
<h4>Next topic</h4>
|
||
<p class="topless"><a href="Beginner-Tutorial-Rules.html"
|
||
title="next chapter"><span class="section-number">2. </span>Rules and dice rolling</a></p>
|
||
<div role="note" aria-label="source link">
|
||
<!--h3>This Page</h3-->
|
||
<ul class="this-page-menu">
|
||
<li><a href="../../../_sources/Howtos/Beginner-Tutorial/Part3/Beginner-Tutorial-Utilities.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="Beginner-Tutorial-Utilities.html">1.0 (main 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="code-structure-and-utilities">
|
||
<h1><span class="section-number">1. </span>Code structure and Utilities<a class="headerlink" href="#code-structure-and-utilities" title="Permalink to this headline">¶</a></h1>
|
||
<p>In this lesson we will set up the file structure for <em>EvAdventure</em>. We will make some
|
||
utilities that will be useful later. We will also learn how to write <em>tests</em>.</p>
|
||
<section id="folder-structure">
|
||
<h2><span class="section-number">1.1. </span>Folder structure<a class="headerlink" href="#folder-structure" title="Permalink to this headline">¶</a></h2>
|
||
<p>Create a new folder under your <code class="docutils literal notranslate"><span class="pre">mygame</span></code> folder, named <code class="docutils literal notranslate"><span class="pre">evadventure</span></code>. Inside it, create
|
||
another folder <code class="docutils literal notranslate"><span class="pre">tests/</span></code> and make sure to put empty <code class="docutils literal notranslate"><span class="pre">__init__.py</span></code> files in both. This turns both
|
||
folders into packages Python understands to import from.</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">mygame</span><span class="o">/</span>
|
||
<span class="n">commands</span><span class="o">/</span>
|
||
<span class="n">evadventure</span><span class="o">/</span> <span class="o"><---</span>
|
||
<span class="fm">__init__</span><span class="o">.</span><span class="n">py</span> <span class="o"><---</span>
|
||
<span class="n">tests</span><span class="o">/</span> <span class="o"><---</span>
|
||
<span class="fm">__init__</span><span class="o">.</span><span class="n">py</span> <span class="o"><---</span>
|
||
<span class="fm">__init__</span><span class="o">.</span><span class="n">py</span>
|
||
<span class="n">README</span><span class="o">.</span><span class="n">md</span>
|
||
<span class="n">server</span><span class="o">/</span>
|
||
<span class="n">typeclasses</span><span class="o">/</span>
|
||
<span class="n">web</span><span class="o">/</span>
|
||
<span class="n">world</span><span class="o">/</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>Importing anything from inside this folder from anywhere else under <code class="docutils literal notranslate"><span class="pre">mygame</span></code> will be done by</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># from anywhere in mygame/</span>
|
||
<span class="kn">from</span> <span class="nn">evadventure.yourmodulename</span> <span class="kn">import</span> <span class="n">whatever</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This is the ‘absolute path` type of import.</p>
|
||
<p>Between two modules both in <code class="docutils literal notranslate"><span class="pre">evadventure/</span></code>, you can use a ‘relative’ import with <code class="docutils literal notranslate"><span class="pre">.</span></code>:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># from a module inside mygame/evadventure</span>
|
||
<span class="kn">from</span> <span class="nn">.yourmodulename</span> <span class="kn">import</span> <span class="n">whatever</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>From e.g. inside <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/tests/</span></code> you can import from one level above using <code class="docutils literal notranslate"><span class="pre">..</span></code>:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># from mygame/evadventure/tests/ </span>
|
||
<span class="kn">from</span> <span class="nn">..yourmodulename</span> <span class="kn">import</span> <span class="n">whatever</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="enums">
|
||
<h2><span class="section-number">1.2. </span>Enums<a class="headerlink" href="#enums" title="Permalink to this headline">¶</a></h2>
|
||
<aside class="sidebar">
|
||
<p>A full example of the enum module is found in
|
||
<a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.enums.html"><span class="doc std std-doc">evennia/contrib/tutorials/evadventure/enums.py</span></a>.</p>
|
||
</aside>
|
||
<p>Create a new file <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/enums.py</span></code>.</p>
|
||
<p>An <a class="reference external" href="https://docs.python.org/3/library/enum.html">enum</a> (enumeration) is a way to establish constants
|
||
in Python. Best is to show an example:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in a file mygame/evadventure/enums.py</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">enum</span> <span class="kn">import</span> <span class="n">Enum</span>
|
||
|
||
<span class="k">class</span> <span class="nc">Ability</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
|
||
|
||
<span class="n">STR</span> <span class="o">=</span> <span class="s2">"strength"</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>You access an enum like this:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># from another module in mygame/evadventure</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">.enums</span> <span class="kn">import</span> <span class="n">Ability</span>
|
||
|
||
<span class="n">Ability</span><span class="o">.</span><span class="n">STR</span> <span class="c1"># the enum itself </span>
|
||
<span class="n">Ability</span><span class="o">.</span><span class="n">STR</span><span class="o">.</span><span class="n">value</span> <span class="c1"># this is the string "strength"</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>Having enums is recommended practice. With them set up, it means we can make sure to refer to the
|
||
same thing every time. Having all enums in one place also means you have a good overview of the
|
||
constants you are dealing with.</p>
|
||
<p>The alternative would be to for example pass around a string <code class="docutils literal notranslate"><span class="pre">"constitution"</span></code>. If you mis-spell
|
||
this (<code class="docutils literal notranslate"><span class="pre">"consitution"</span></code>), you would not necessarily know it right away - the error would happen later
|
||
when the string is not recognized. If you make a typo getting <code class="docutils literal notranslate"><span class="pre">Ability.COM</span></code> instead of <code class="docutils literal notranslate"><span class="pre">Ability.CON</span></code>,
|
||
Python will immediately raise an error since this enum is not recognized.</p>
|
||
<p>With enums you can also do nice direct comparisons like <code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">ability</span> <span class="pre">is</span> <span class="pre">Ability.WIS:</span> <span class="pre"><do</span> <span class="pre">stuff></span></code>.</p>
|
||
<p>Note that the <code class="docutils literal notranslate"><span class="pre">Ability.STR</span></code> enum does not have the actual <em>value</em> of e.g. your Strength.
|
||
It’s just a fixed label for the Strength ability.</p>
|
||
<p>Here is the <code class="docutils literal notranslate"><span class="pre">enum.py</span></code> module needed for <em>Knave</em>. It covers the basic aspects of
|
||
rule systems we need to track (check out the <em>Knave</em> rules. If you use another rule system you’ll
|
||
likely gradually expand on your enums as you figure out what you’ll need).</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/enums.py</span>
|
||
|
||
<span class="k">class</span> <span class="nc">Ability</span><span class="p">(</span><span class="n">Enum</span><span class="p">):</span>
|
||
<span class="sd">"""</span>
|
||
<span class="sd"> The six base ability-bonuses and other </span>
|
||
<span class="sd"> abilities</span>
|
||
|
||
<span class="sd"> """</span>
|
||
|
||
<span class="n">STR</span> <span class="o">=</span> <span class="s2">"strength"</span>
|
||
<span class="n">DEX</span> <span class="o">=</span> <span class="s2">"dexterity"</span>
|
||
<span class="n">CON</span> <span class="o">=</span> <span class="s2">"constitution"</span>
|
||
<span class="n">INT</span> <span class="o">=</span> <span class="s2">"intelligence"</span>
|
||
<span class="n">WIS</span> <span class="o">=</span> <span class="s2">"wisdom"</span>
|
||
<span class="n">CHA</span> <span class="o">=</span> <span class="s2">"charisma"</span>
|
||
|
||
<span class="n">ARMOR</span> <span class="o">=</span> <span class="s2">"armor"</span>
|
||
|
||
<span class="n">CRITICAL_FAILURE</span> <span class="o">=</span> <span class="s2">"critical_failure"</span>
|
||
<span class="n">CRITICAL_SUCCESS</span> <span class="o">=</span> <span class="s2">"critical_success"</span>
|
||
|
||
<span class="n">ALLEGIANCE_HOSTILE</span> <span class="o">=</span> <span class="s2">"hostile"</span>
|
||
<span class="n">ALLEGIANCE_NEUTRAL</span> <span class="o">=</span> <span class="s2">"neutral"</span>
|
||
<span class="n">ALLEGIANCE_FRIENDLY</span> <span class="o">=</span> <span class="s2">"friendly"</span>
|
||
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>Here the <code class="docutils literal notranslate"><span class="pre">Ability</span></code> class holds basic properties of a character sheet.</p>
|
||
</section>
|
||
<section id="utility-module">
|
||
<h2><span class="section-number">1.3. </span>Utility module<a class="headerlink" href="#utility-module" title="Permalink to this headline">¶</a></h2>
|
||
<blockquote>
|
||
<div><p>Create a new module <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/utils.py</span></code></p>
|
||
</div></blockquote>
|
||
<aside class="sidebar">
|
||
<p>An example of the utility module is found in
|
||
<a class="reference internal" href="../../../api/evennia.contrib.tutorials.evadventure.utils.html"><span class="doc std std-doc">evennia/contrib/tutorials/evadventure/utils.py</span></a></p>
|
||
</aside>
|
||
<p>This is for general functions we may need from all over. In this case we only picture one utility,
|
||
a function that produces a pretty display of any object we pass to it.</p>
|
||
<p>This is an example of the string we want to see:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">Chipped</span> <span class="n">Sword</span>
|
||
<span class="n">Value</span><span class="p">:</span> <span class="o">~</span><span class="mi">10</span> <span class="n">coins</span> <span class="p">[</span><span class="n">wielded</span> <span class="ow">in</span> <span class="n">Weapon</span> <span class="n">hand</span><span class="p">]</span>
|
||
|
||
<span class="n">A</span> <span class="n">simple</span> <span class="n">sword</span> <span class="n">used</span> <span class="n">by</span> <span class="n">mercenaries</span> <span class="nb">all</span> <span class="n">over</span>
|
||
<span class="n">the</span> <span class="n">world</span><span class="o">.</span>
|
||
|
||
<span class="n">Slots</span><span class="p">:</span> <span class="mi">1</span><span class="p">,</span> <span class="n">Used</span> <span class="n">from</span><span class="p">:</span> <span class="n">weapon</span> <span class="n">hand</span>
|
||
<span class="n">Quality</span><span class="p">:</span> <span class="mi">3</span><span class="p">,</span> <span class="n">Uses</span><span class="p">:</span> <span class="kc">None</span>
|
||
<span class="n">Attacks</span> <span class="n">using</span> <span class="n">strength</span> <span class="n">against</span> <span class="n">armor</span><span class="o">.</span>
|
||
<span class="n">Damage</span> <span class="n">roll</span><span class="p">:</span> <span class="mi">1</span><span class="n">d6</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Here’s the start of how the function could look:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/evadventure/utils.py</span>
|
||
|
||
<span class="n">_OBJ_STATS</span> <span class="o">=</span> <span class="s2">"""</span>
|
||
<span class="s2">|c</span><span class="si">{key}</span><span class="s2">|n</span>
|
||
<span class="s2">Value: ~|y</span><span class="si">{value}</span><span class="s2">|n coins</span><span class="si">{carried}</span><span class="s2"></span>
|
||
|
||
<span class="si">{desc}</span><span class="s2"></span>
|
||
|
||
<span class="s2">Slots: |w</span><span class="si">{size}</span><span class="s2">|n, Used from: |w</span><span class="si">{use_slot_name}</span><span class="s2">|n</span>
|
||
<span class="s2">Quality: |w</span><span class="si">{quality}</span><span class="s2">|n, Uses: |wuses|n</span>
|
||
<span class="s2">Attacks using |w</span><span class="si">{attack_type_name}</span><span class="s2">|n against |w</span><span class="si">{defense_type_name}</span><span class="s2">|n</span>
|
||
<span class="s2">Damage roll: |w</span><span class="si">{damage_roll}</span><span class="s2">|n</span>
|
||
<span class="s2">"""</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
|
||
|
||
|
||
<span class="k">def</span> <span class="nf">get_obj_stats</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">owner</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||
<span class="sd">""" </span>
|
||
<span class="sd"> Get a string of stats about the object.</span>
|
||
<span class="sd"> </span>
|
||
<span class="sd"> Args:</span>
|
||
<span class="sd"> obj (Object): The object to get stats for.</span>
|
||
<span class="sd"> owner (Object): The one currently owning/carrying `obj`, if any. Can be </span>
|
||
<span class="sd"> used to show e.g. where they are wielding it.</span>
|
||
<span class="sd"> Returns:</span>
|
||
<span class="sd"> str: A nice info string to display about the object.</span>
|
||
<span class="sd"> </span>
|
||
<span class="sd"> """</span>
|
||
<span class="k">return</span> <span class="n">_OBJ_STATS</span><span class="o">.</span><span class="n">format</span><span class="p">(</span>
|
||
<span class="n">key</span><span class="o">=</span><span class="n">obj</span><span class="o">.</span><span class="n">key</span><span class="p">,</span>
|
||
<span class="n">value</span><span class="o">=</span><span class="mi">10</span><span class="p">,</span>
|
||
<span class="n">carried</span><span class="o">=</span><span class="s2">"[Not carried]"</span><span class="p">,</span>
|
||
<span class="n">desc</span><span class="o">=</span><span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">desc</span><span class="p">,</span>
|
||
<span class="n">size</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span>
|
||
<span class="n">quality</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span>
|
||
<span class="n">uses</span><span class="o">=</span><span class="s2">"infinite"</span>
|
||
<span class="n">use_slot_name</span><span class="o">=</span><span class="s2">"backpack"</span><span class="p">,</span>
|
||
<span class="n">attack_type_name</span><span class="o">=</span><span class="s2">"strength"</span>
|
||
<span class="n">defense_type_name</span><span class="o">=</span><span class="s2">"armor"</span>
|
||
<span class="n">damage_roll</span><span class="o">=</span><span class="s2">"1d6"</span>
|
||
<span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Here we set up the string template with place holders for where every piece of info should go.
|
||
Study this string so you understand what it does. The <code class="docutils literal notranslate"><span class="pre">|c</span></code>, <code class="docutils literal notranslate"><span class="pre">|y</span></code>, <code class="docutils literal notranslate"><span class="pre">|w</span></code> and <code class="docutils literal notranslate"><span class="pre">|n</span></code> markers are
|
||
<a class="reference internal" href="../../../Concepts/Colors.html"><span class="doc std std-doc">Evennia color markup</span></a> for making the text cyan, yellow, white and neutral-color respectively.</p>
|
||
<p>We can guess some things, such that <code class="docutils literal notranslate"><span class="pre">obj.key</span></code> is the name of the object, and that <code class="docutils literal notranslate"><span class="pre">obj.db.desc</span></code> will
|
||
hold its description (this is how it is in default Evennia).</p>
|
||
<p>But so far we have not established how to get any of the other properties like <code class="docutils literal notranslate"><span class="pre">size</span></code> or <code class="docutils literal notranslate"><span class="pre">attack_type</span></code>.
|
||
So we just set them to dummy values. We’ll need to get back to this when we have more code in place!</p>
|
||
</section>
|
||
<section id="testing">
|
||
<h2><span class="section-number">1.4. </span>Testing<a class="headerlink" href="#testing" title="Permalink to this headline">¶</a></h2>
|
||
<div class="admonition important">
|
||
<p class="admonition-title">Important</p>
|
||
<p>It’s useful for any game dev to know how to effectively test their code. So we’ll try to include a
|
||
<em>Testing</em> section at the end of each of the implementation lessons to follow. Writing tests for your code
|
||
is optional but highly recommended; it can feel a little cumbersome at first, but you’ll thank yourself later.</p>
|
||
</div>
|
||
<blockquote>
|
||
<div><p>create a new module <code class="docutils literal notranslate"><span class="pre">mygame/evadventure/tests/test_utils.py</span></code></p>
|
||
</div></blockquote>
|
||
<p>How do you know if you made a typo in the code above? You could <em>manually</em> test it by reloading your
|
||
Evennia server and do the following from in-game:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>py from evadventure.utils import get_obj_stats;print(get_obj_stats(self))
|
||
</pre></div>
|
||
</div>
|
||
<p>You should get back a nice string about yourself! If that works, great! But you’ll need to remember
|
||
doing that test when you change this code later.</p>
|
||
<aside class="sidebar">
|
||
<p>In [evennia/contrib/tutorials/evadventure/tests/test_utils.py](evennia.contrib.tutorials.
|
||
evadventure.tests.test_utils)
|
||
is an example of the testing module. To dive deeper into unit testing in Evennia, see the
|
||
<a class="reference internal" href="../../../Coding/Unit-Testing.html"><span class="doc std std-doc">Unit testing</span></a> documentation.</p>
|
||
</aside>
|
||
<p>A <em>unit test</em> allows you to set up automated testing of code. Once you’ve written your test you
|
||
can run it over and over and make sure later changes to your code didn’t break things.</p>
|
||
<p>In this particular case, we <em>expect</em> to later have to update the test when <code class="docutils literal notranslate"><span class="pre">get_obj_stats</span></code> becomes more
|
||
complete and returns more reasonable data.</p>
|
||
<p>Evennia comes with extensive functionality to help you test your code. Here’s a module for
|
||
testing <code class="docutils literal notranslate"><span class="pre">get_obj_stats</span></code>.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/evadventure/tests/test_utils.py</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">create</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">..import</span> <span class="n">utils</span>
|
||
|
||
<span class="k">class</span> <span class="nc">TestUtils</span><span class="p">(</span><span class="n">BaseEvenniaTest</span><span class="p">):</span>
|
||
<span class="k">def</span> <span class="nf">test_get_obj_stats</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="c1"># make a simple object to test with </span>
|
||
<span class="n">obj</span> <span class="o">=</span> <span class="n">create</span><span class="o">.</span><span class="n">create_object</span><span class="p">(</span>
|
||
<span class="n">key</span><span class="o">=</span><span class="s2">"testobj"</span><span class="p">,</span>
|
||
<span class="n">attributes</span><span class="o">=</span><span class="p">((</span><span class="s2">"desc"</span><span class="p">,</span> <span class="s2">"A test object"</span><span class="p">),)</span>
|
||
<span class="p">)</span>
|
||
<span class="c1"># run it through the function </span>
|
||
<span class="n">result</span> <span class="o">=</span> <span class="n">utils</span><span class="o">.</span><span class="n">get_obj_stats</span><span class="p">(</span><span class="n">obj</span><span class="p">)</span>
|
||
<span class="c1"># check that the result is what we expected</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span>
|
||
<span class="n">result</span><span class="p">,</span>
|
||
<span class="sd">""" </span>
|
||
<span class="sd">|ctestobj|n</span>
|
||
<span class="sd">Value: ~|y10|n coins</span>
|
||
|
||
<span class="sd">A test object</span>
|
||
|
||
<span class="sd">Slots: |w1|n, Used from: |wbackpack|n</span>
|
||
<span class="sd">Quality: |w3|n, Uses: |winfinite|n</span>
|
||
<span class="sd">Attacks using |wstrength|n against |warmor|n</span>
|
||
<span class="sd">Damage roll: |w1d6|n</span>
|
||
<span class="sd">"""</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span>
|
||
<span class="p">)</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>What happens here is that we create a new test-class <code class="docutils literal notranslate"><span class="pre">TestUtils</span></code> that inherits from <code class="docutils literal notranslate"><span class="pre">BaseEvenniaTest</span></code>.
|
||
This inheritance is what makes this a testing class.</p>
|
||
<p>We can have any number of methods on this class. To have a method recognized as one containing
|
||
code to test, its name <em>must</em> start with <code class="docutils literal notranslate"><span class="pre">test_</span></code>. We have one - <code class="docutils literal notranslate"><span class="pre">test_get_obj_stats</span></code>.</p>
|
||
<p>In this method we create a dummy <code class="docutils literal notranslate"><span class="pre">obj</span></code> and gives it a <code class="docutils literal notranslate"><span class="pre">key</span></code> “testobj”. Note how we add the
|
||
<code class="docutils literal notranslate"><span class="pre">desc</span></code> <a class="reference internal" href="../../../Components/Attributes.html"><span class="doc std std-doc">Attribute</span></a> directly in the <code class="docutils literal notranslate"><span class="pre">create_object</span></code> call by specifying the attribute as a
|
||
tuple <code class="docutils literal notranslate"><span class="pre">(name,</span> <span class="pre">value)</span></code>!</p>
|
||
<p>We then get the result of passing this dummy-object through <code class="docutils literal notranslate"><span class="pre">get_obj_stats</span></code> we imported earlier.</p>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">assertEqual</span></code> method is available on all testing classes and checks that the <code class="docutils literal notranslate"><span class="pre">result</span></code> is equal
|
||
to the string we specify. If they are the same, the test <em>passes</em>, otherwise it <em>fails</em> and we
|
||
need to investigate what went wrong.</p>
|
||
<section id="running-your-test">
|
||
<h3><span class="section-number">1.4.1. </span>Running your test<a class="headerlink" href="#running-your-test" title="Permalink to this headline">¶</a></h3>
|
||
<p>To run your test you need to stand inside your <code class="docutils literal notranslate"><span class="pre">mygame</span></code> folder and execute the following command:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evennia test --settings settings.py .evadventure.tests
|
||
</pre></div>
|
||
</div>
|
||
<p>This will run all your <code class="docutils literal notranslate"><span class="pre">evadventure</span></code> tests (if you had more of them). To only run your utility tests
|
||
you could do</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evennia test --settings settings.py .evadventure.tests.test_utils
|
||
</pre></div>
|
||
</div>
|
||
<p>If all goes well, you should get an <code class="docutils literal notranslate"><span class="pre">OK</span></code> back. Otherwise you need to check the failure, maybe
|
||
your return string doesn’t quite match what you expected.</p>
|
||
</section>
|
||
</section>
|
||
<section id="summary">
|
||
<h2><span class="section-number">1.5. </span>Summary<a class="headerlink" href="#summary" title="Permalink to this headline">¶</a></h2>
|
||
<p>It’s very important to understand how you import code between modules in Python, so if this is still
|
||
confusing to you, it’s worth to read up on this more.</p>
|
||
<p>That said, many newcomers are confused with how to begin, so by creating the folder structure, some
|
||
small modules and even making your first unit test, you are off to a great start!</p>
|
||
</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="Beginner-Tutorial-Rules.html" title="2. Rules and dice rolling"
|
||
>next</a> |</li>
|
||
<li class="right" >
|
||
<a href="Beginner-Tutorial-Part3-Overview.html" title="Part 3: How we get there (example game)"
|
||
>previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia 1.0</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="../../Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||
<li class="nav-item nav-item-2"><a href="../Beginner-Tutorial-Overview.html" >Beginner Tutorial</a> »</li>
|
||
<li class="nav-item nav-item-3"><a href="Beginner-Tutorial-Part3-Overview.html" >Part 3: How we get there (example game)</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href=""><span class="section-number">1. </span>Code structure and Utilities</a></li>
|
||
</ul>
|
||
</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> |