Sophie

Sophie

distrib > Fedora > 17 > i386 > media > updates > by-pkgid > b50d8ee6d7871fcc13c0677a9364ed59 > files > 366

bcfg2-doc-1.3.0-1.fc17.noarch.rpm



<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    
    <title>Bcfg2 unit testing &mdash; Bcfg2 1.3.0 documentation</title>
    
    <link rel="stylesheet" href="../_static/default.css" type="text/css" />
    <link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
    
    <script type="text/javascript">
      var DOCUMENTATION_OPTIONS = {
        URL_ROOT:    '../',
        VERSION:     '1.3.0',
        COLLAPSE_INDEX: false,
        FILE_SUFFIX: '.html',
        HAS_SOURCE:  true
      };
    </script>
    <script type="text/javascript" src="../_static/jquery.js"></script>
    <script type="text/javascript" src="../_static/underscore.js"></script>
    <script type="text/javascript" src="../_static/doctools.js"></script>
    <script type="text/javascript" src="../_static/sidebar.js"></script>
    <link rel="shortcut icon" href="../_static/favicon.ico"/>
    <link rel="top" title="Bcfg2 1.3.0 documentation" href="../index.html" />
    <link rel="up" title="Bcfg2 Development" href="index.html" />
    <link rel="next" title="Versioning Bcfg2" href="versioning.html" />
    <link rel="prev" title="Tips for Bcfg2 Development" href="tips.html" />
 
<link rel="stylesheet" href="../_static/bcfg2.css" type=""/>

  </head>
  <body>

<div style="text-align: left; padding: 10px 10px 15px 15px">
<a href="../index.html"><img src="../_static/bcfg2_logo.png" border="0" alt="sampledoc"/></a>
</div>

    <div class="related">
      <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="versioning.html" title="Versioning Bcfg2"
             accesskey="N">next</a> |</li>
        <li class="right" >
          <a href="tips.html" title="Tips for Bcfg2 Development"
             accesskey="P">previous</a> |</li>
	<li><a href="../index.html">home</a> |&nbsp;</li>
	<!--<li><a href="../search.html">search</a> |&nbsp;</li>-->
	<li><a href="../help/index.html">help</a> |&nbsp;</li>
	<li><a href="../contents.html">documentation </a> &raquo;</li>

          <li><a href="../contents.html" >Bcfg2 documentation 1.3.0</a> &raquo;</li>
          <li><a href="index.html" accesskey="U">Bcfg2 Development</a> &raquo;</li> 
      </ul>
    </div>
  

    <div class="document">
      <div class="documentwrapper">
        <div class="bodywrapper">
          <div class="body">
            
  <div class="section" id="bcfg2-unit-testing">
<span id="development-unit-testing"></span><h1>Bcfg2 unit testing<a class="headerlink" href="#bcfg2-unit-testing" title="Permalink to this headline">¶</a></h1>
<p>You will first need to install the <a class="reference external" href="http://www.voidspace.org.uk/python/mock">Python Mock Module</a> and <a class="reference external" href="http://readthedocs.org/docs/nose/en/latest/">Python
Nose</a> modules. You can then run the existing tests with the
following:</p>
<p>You should see output something like the following:</p>
<div class="highlight-python"><pre>..................................................
----------------------------------------------------------------------
Ran 50 tests in 0.121s

OK</pre>
</div>
<p>Unit tests are also run by Travis-CI, a free continuous integration
service, at <a class="reference external" href="http://travis-ci.org/#!/Bcfg2/bcfg2/">http://travis-ci.org/#!/Bcfg2/bcfg2/</a></p>
<div class="section" id="testing-in-a-virtualenv">
<h2>Testing in a virtualenv<a class="headerlink" href="#testing-in-a-virtualenv" title="Permalink to this headline">¶</a></h2>
<p>Travis-CI runs the unit tests in a virtual environment, so to emulate
that testing environment as closely as possible you can also use a
virtual environment.  To do so, you must have <a class="reference external" href="http://www.virtualenv.org/">virtualenv</a> installed.</p>
<p>There are two ways to test: Either with just the bare essential
packages installed, or with optional packages installed as well.
(Optional packages are things like Genshi; you can run Bcfg2 with them
or without them.)  For completeness, the tests should be run in both
manners.  (On Python 3, almost none of the optional packages are
available, so it can only be run with just the required packages.)  To
install the optional packages, set:</p>
<div class="highlight-bash"><div class="highlight"><pre><span class="nb">export </span><span class="nv">WITH_OPTIONAL_DEPS</span><span class="o">=</span>yes
</pre></div>
</div>
<p>This flag tells the install script to install optional dependencies as
well as requirements.</p>
<p>This assumes that you will create a virtual environment in
<tt class="docutils literal"><span class="pre">~/venvs/</span></tt>, and that the Bcfg2 source tree is cloned into
<tt class="docutils literal"><span class="pre">~/bcfg2</span></tt>.</p>
<p>First, create a new virtual environment and activate it:</p>
<div class="highlight-bash"><div class="highlight"><pre><span class="nb">cd</span> ~/venvs
virtualenv travis
<span class="nb">source </span>travis/bin/activate
</pre></div>
</div>
<p>Get the test suite from bcfg2:</p>
<div class="highlight-bash"><div class="highlight"><pre>cp -R ~/bcfg2/* ~/venvs/travis/
</pre></div>
</div>
<p>Next, you must install prerequisite packages that are required to
build some of the required Python packages, and some optional packages
that are much easier to install from binary (rather than from source).
If you are running on Ubuntu (the platform Travis-CI runs on) and have
sudo, you can simply run:</p>
<div class="highlight-bash"><div class="highlight"><pre>testsuite/before_install.sh
</pre></div>
</div>
<p>If not, you will need to examine <tt class="docutils literal"><span class="pre">testsuite/before_install.sh</span></tt>
and install the packages manually.  The equivalent for Fedora, for
instance, would be:</p>
<div class="highlight-bash"><div class="highlight"><pre>sudo yum -y update
sudo yum -y install swig pylint libxml2
<span class="k">if</span> <span class="o">[[</span> <span class="s2">&quot;$WITH_OPTIONAL_DEPS&quot;</span> <span class="o">==</span> <span class="s2">&quot;yes&quot;</span> <span class="o">]]</span>; <span class="k">then</span>
<span class="k">    </span>sudo yum -y install libselinux-python pylibacl python-inotify <span class="se">\</span>
        PyYAML
<span class="k">fi</span>
</pre></div>
</div>
<p>You could install these requirements using pip, but you&#8217;ll likely need
to install a great many development packages required to compile them.</p>
<p>Next, install required Python packages:</p>
<div class="highlight-bash"><div class="highlight"><pre>testsuite/install.sh
</pre></div>
</div>
<p>Install Bcfg2 itself to the virtualenv:</p>
<div class="highlight-bash"><div class="highlight"><pre>pip install -e .
</pre></div>
</div>
<p>Now you can run tests:</p>
<div class="highlight-bash"><div class="highlight"><pre>nosetests testsuite
</pre></div>
</div>
</div>
<div class="section" id="writing-unit-tests">
<h2>Writing Unit Tests<a class="headerlink" href="#writing-unit-tests" title="Permalink to this headline">¶</a></h2>
<p>Bcfg2 makes extremely heavy use of object inheritance, which can make
it challenging at times to write reusable tests.  For instance, when
writing tests for the base <a class="reference internal" href="plugins.html#Bcfg2.Server.Plugin.base.Plugin" title="Bcfg2.Server.Plugin.base.Plugin"><tt class="xref py py-class docutils literal"><span class="pre">Bcfg2.Server.Plugin.base.Plugin</span></tt></a>
class, which all Bcfg2 <a class="reference internal" href="../server/plugins/index.html#server-plugins-index"><em>Plugins</em></a> inherit from via
the <a class="reference internal" href="plugins.html#module-Bcfg2.Server.Plugin.interfaces" title="Bcfg2.Server.Plugin.interfaces"><tt class="xref py py-mod docutils literal"><span class="pre">Plugin</span> <span class="pre">interfaces</span></tt></a>,
yielding several levels of often-multiple inheritance.  To make this
easier, our unit tests adhere to several design considerations:</p>
<div class="section" id="inherit-tests">
<h3>Inherit Tests<a class="headerlink" href="#inherit-tests" title="Permalink to this headline">¶</a></h3>
<p>Our test objects should have inheritance trees that mirror the
inheritance trees of their tested objects.  For instance, the
<tt class="xref py py-class docutils literal"><span class="pre">Bcfg2.Server.Plugins.Metadata.Metadata</span></tt> class definition is:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">Metadata</span><span class="p">(</span><span class="n">Bcfg2</span><span class="o">.</span><span class="n">Server</span><span class="o">.</span><span class="n">Plugin</span><span class="o">.</span><span class="n">Metadata</span><span class="p">,</span>
               <span class="n">Bcfg2</span><span class="o">.</span><span class="n">Server</span><span class="o">.</span><span class="n">Plugin</span><span class="o">.</span><span class="n">Statistics</span><span class="p">,</span>
               <span class="n">Bcfg2</span><span class="o">.</span><span class="n">Server</span><span class="o">.</span><span class="n">Plugin</span><span class="o">.</span><span class="n">DatabaseBacked</span><span class="p">):</span>
</pre></div>
</div>
<p>Consequently, the <tt class="docutils literal"><span class="pre">TestMetadata</span></tt> class definition is:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">TestMetadata</span><span class="p">(</span><span class="n">TestPlugin</span><span class="o">.</span><span class="n">TestMetadata</span><span class="p">,</span>
                   <span class="n">TestPlugin</span><span class="o">.</span><span class="n">TestStatistics</span><span class="p">,</span>
                   <span class="n">TestPlugin</span><span class="o">.</span><span class="n">TestDatabaseBacked</span><span class="p">):</span>
</pre></div>
</div>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">The test object names are abbreviated because of the system of
relative imports in the <tt class="docutils literal"><span class="pre">testsuite</span></tt> tree, described below.</p>
</div>
<p>This gives us a large number of tests basically &#8220;for free&#8221;: all core
<a class="reference internal" href="plugins.html#Bcfg2.Server.Plugin.interfaces.Metadata" title="Bcfg2.Server.Plugin.interfaces.Metadata"><tt class="xref py py-class docutils literal"><span class="pre">Bcfg2.Server.Plugin.interfaces.Metadata</span></tt></a>,
<a class="reference internal" href="plugins.html#Bcfg2.Server.Plugin.interfaces.Statistics" title="Bcfg2.Server.Plugin.interfaces.Statistics"><tt class="xref py py-class docutils literal"><span class="pre">Bcfg2.Server.Plugin.interfaces.Statistics</span></tt></a>, and
<a class="reference internal" href="plugins.html#Bcfg2.Server.Plugin.helpers.DatabaseBacked" title="Bcfg2.Server.Plugin.helpers.DatabaseBacked"><tt class="xref py py-class docutils literal"><span class="pre">Bcfg2.Server.Plugin.helpers.DatabaseBacked</span></tt></a> functionality is
automatically tested on the <tt class="docutils literal"><span class="pre">Metadata</span></tt> class, which gives the test
writer a lot of free functionality and also an easy list of which
tests must be overridden to provide tests appropriate for the <tt class="docutils literal"><span class="pre">Metadata</span></tt>
class implementation.</p>
<p>Additionally, a test class should have a class variable that describes
the class that is being tested, and tests in that class should use
that class variable to instantate the tested object.  For instance,
the test for <a class="reference internal" href="plugins.html#Bcfg2.Server.Plugin.helpers.DirectoryBacked" title="Bcfg2.Server.Plugin.helpers.DirectoryBacked"><tt class="xref py py-class docutils literal"><span class="pre">Bcfg2.Server.Plugin.helpers.DirectoryBacked</span></tt></a>
looks like this:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">TestDirectoryBacked</span><span class="p">(</span><span class="n">Bcfg2TestCase</span><span class="p">):</span>
    <span class="n">test_obj</span> <span class="o">=</span> <span class="n">DirectoryBacked</span>
    <span class="o">...</span>


    <span class="k">def</span> <span class="nf">test_child_interface</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot; ensure that the child object has the correct interface &quot;&quot;&quot;</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">assertTrue</span><span class="p">(</span><span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">test_obj</span><span class="o">.</span><span class="n">__child__</span><span class="p">,</span> <span class="s">&quot;HandleEvent&quot;</span><span class="p">))</span>
</pre></div>
</div>
<p>Then test objects that inherit from <tt class="docutils literal"><span class="pre">TestDirectoryBacked</span></tt> can
override that object, and the <tt class="docutils literal"><span class="pre">test_child_interface</span></tt> test (e.g.)
will still work.  For example:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">TestPropDirectoryBacked</span><span class="p">(</span><span class="n">TestDirectoryBacked</span><span class="p">):</span>
    <span class="n">test_obj</span> <span class="o">=</span> <span class="n">PropDirectoryBacked</span>
</pre></div>
</div>
<p>Finally, each test class must also provide a <tt class="docutils literal"><span class="pre">get_obj</span></tt> method that
takes no required arguments and produces an instance of <tt class="docutils literal"><span class="pre">test_obj</span></tt>.
All test methods must use <tt class="docutils literal"><span class="pre">self.get_obj()</span></tt> to instantiate an object
to be tested.</p>
<p>An object that does not inherit from any other tested Bcfg2 objects
should inherit from <tt class="xref py py-class docutils literal"><span class="pre">testsuite.common.Bcfg2TestCase</span></tt>, described
below.</p>
</div>
<div class="section" id="relative-imports">
<span id="development-unit-testing-relative-imports"></span><h3>Relative Imports<a class="headerlink" href="#relative-imports" title="Permalink to this headline">¶</a></h3>
<p>In order to reuse test code and allow for test inheritance, each test
module should add all parent module paths to its <tt class="docutils literal"><span class="pre">sys.path</span></tt>.  For
instance, assuming a test in
<tt class="docutils literal"><span class="pre">testsuite/Testsrc/Testlib/TestServer/TestPlugins/TestMetadata.py</span></tt>,
the following paths should be added to <tt class="docutils literal"><span class="pre">sys.path</span></tt>:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="n">testsuite</span>
<span class="n">testsuite</span><span class="o">/</span><span class="n">Testsrc</span>
<span class="n">testsuite</span><span class="o">/</span><span class="n">Testsrc</span><span class="o">/</span><span class="n">Testlib</span>
<span class="n">testsuite</span><span class="o">/</span><span class="n">Testsrc</span><span class="o">/</span><span class="n">Testlib</span><span class="o">/</span><span class="n">TestServer</span>
<span class="n">testsuite</span><span class="o">/</span><span class="n">Testsrc</span><span class="o">/</span><span class="n">Testlib</span><span class="o">/</span><span class="n">TestServer</span><span class="o">/</span><span class="n">TestPlugins</span>
</pre></div>
</div>
<p>This must be done because Python 2.4, one of our target platforms,
does not support relative imports.  An easy way to do this is to add
the following snippet to the top of each test file:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">sys</span>

<span class="c"># add all parent testsuite directories to sys.path to allow (most)</span>
<span class="c"># relative imports in python 2.4</span>
<span class="n">path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">__file__</span><span class="p">)</span>
<span class="k">while</span> <span class="n">path</span> <span class="o">!=</span> <span class="s">&quot;/&quot;</span><span class="p">:</span>
    <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">path</span><span class="p">)</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">&quot;test&quot;</span><span class="p">):</span>
        <span class="n">sys</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span><span class="n">path</span><span class="p">)</span> <span class="o">==</span> <span class="s">&quot;testsuite&quot;</span><span class="p">:</span>
        <span class="k">break</span>
    <span class="n">path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
</pre></div>
</div>
<p>In addition, each new directory created in <tt class="docutils literal"><span class="pre">testsuite</span></tt> must contain
an empty <tt class="docutils literal"><span class="pre">__init__.py</span></tt>.</p>
<p>This will allow you, within <tt class="docutils literal"><span class="pre">TestMetadata.py</span></tt>, to import common test
code and the parent objects the <tt class="docutils literal"><span class="pre">TestMetadata</span></tt> class will inherit from:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">common</span> <span class="kn">import</span> <span class="n">inPy3k</span><span class="p">,</span> <span class="n">call</span><span class="p">,</span> <span class="n">builtins</span><span class="p">,</span> <span class="n">u</span><span class="p">,</span> <span class="n">can_skip</span><span class="p">,</span> \
    <span class="n">skip</span><span class="p">,</span> <span class="n">skipIf</span><span class="p">,</span> <span class="n">skipUnless</span><span class="p">,</span> <span class="n">Bcfg2TestCase</span><span class="p">,</span> <span class="n">DBModelTestCase</span><span class="p">,</span> <span class="n">syncdb</span><span class="p">,</span> \
    <span class="n">patchIf</span><span class="p">,</span> <span class="n">datastore</span>
<span class="kn">from</span> <span class="nn">TestPlugin</span> <span class="kn">import</span> <span class="n">TestXMLFileBacked</span><span class="p">,</span> <span class="n">TestMetadata</span> <span class="k">as</span> <span class="n">_TestMetadata</span><span class="p">,</span> \
    <span class="n">TestStatistics</span><span class="p">,</span> <span class="n">TestDatabaseBacked</span>
</pre></div>
</div>
</div>
<div class="section" id="avoid-patching-where-possible">
<h3>Avoid Patching Where Possible<a class="headerlink" href="#avoid-patching-where-possible" title="Permalink to this headline">¶</a></h3>
<p>The <a class="reference external" href="http://www.voidspace.org.uk/python/mock">Python Mock Module</a> provides a <tt class="docutils literal"><span class="pre">patch</span></tt> decorator that can be
used to replace tested objects with <tt class="docutils literal"><span class="pre">Mock</span></tt> objects.  This is
wonderful and necessary, but due to differences in the way various
versions of Python and Python Mock handle object scope, it&#8217;s not
always reliable when combined with our system of test object
inheritance.  Consequently, you should follow these rules when
considering whether to use <tt class="docutils literal"><span class="pre">patch</span></tt>:</p>
<ul class="simple">
<li>If you need to mock an object that is not part of Bcfg2 (e.g., a
builtin or an object in another Python library), use <tt class="docutils literal"><span class="pre">patch</span></tt>.</li>
<li>If you need to patch an object being tested in order to instantiate
it, use <tt class="docutils literal"><span class="pre">patch</span></tt>, but see below.</li>
<li>If you need to patch a function (not a method) that is part of
Bcfg2, use <tt class="docutils literal"><span class="pre">patch</span></tt>.</li>
<li>If you need to mock an object that is part of the object being
tested, do not use <tt class="docutils literal"><span class="pre">patch</span></tt>.</li>
</ul>
<p>As an example of the last rule, assume you are writing tests for
<a class="reference internal" href="plugins.html#Bcfg2.Server.Plugin.helpers.FileBacked" title="Bcfg2.Server.Plugin.helpers.FileBacked"><tt class="xref py py-class docutils literal"><span class="pre">Bcfg2.Server.Plugin.helpers.FileBacked</span></tt></a>.
<a class="reference internal" href="plugins.html#Bcfg2.Server.Plugin.helpers.FileBacked.HandleEvent" title="Bcfg2.Server.Plugin.helpers.FileBacked.HandleEvent"><tt class="xref py py-func docutils literal"><span class="pre">Bcfg2.Server.Plugin.helpers.FileBacked.HandleEvent()</span></tt></a> calls
<a class="reference internal" href="plugins.html#Bcfg2.Server.Plugin.helpers.FileBacked.Index" title="Bcfg2.Server.Plugin.helpers.FileBacked.Index"><tt class="xref py py-func docutils literal"><span class="pre">Bcfg2.Server.Plugin.helpers.FileBacked.Index()</span></tt></a>, so we need to
mock the <tt class="docutils literal"><span class="pre">Index</span></tt> function.  This is the <strong>wrong</strong> way to do that:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">TestFileBacked</span><span class="p">(</span><span class="n">Bcfg2TestCase</span><span class="p">):</span>
    <span class="nd">@patch</span><span class="p">(</span><span class="s">&quot;</span><span class="si">%s</span><span class="s">.open&quot;</span> <span class="o">%</span> <span class="n">builtins</span><span class="p">)</span>
    <span class="nd">@patch</span><span class="p">(</span><span class="s">&quot;Bcfg2.Server.Plugin.helpers.FileBacked.Index&quot;</span><span class="p">)</span>
    <span class="k">def</span> <span class="nf">test_HandleEvent</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">mock_Index</span><span class="p">,</span> <span class="n">mock_open</span><span class="p">):</span>
        <span class="o">...</span>
</pre></div>
</div>
<p>Tests that inherit from <tt class="docutils literal"><span class="pre">TestFileBacked</span></tt> will not reliably patch the
correct <tt class="docutils literal"><span class="pre">Index</span></tt> function.  Instead, assign the object to be mocked
directly:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">TestFileBacked</span><span class="p">(</span><span class="n">Bcfg2TestCase</span><span class="p">):</span>
    <span class="nd">@patch</span><span class="p">(</span><span class="s">&quot;</span><span class="si">%s</span><span class="s">.open&quot;</span> <span class="o">%</span> <span class="n">builtins</span><span class="p">)</span>
    <span class="k">def</span> <span class="nf">test_HandleEvent</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">mock_open</span><span class="p">):</span>
        <span class="n">fb</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_obj</span><span class="p">()</span>
        <span class="n">fb</span><span class="o">.</span><span class="n">Index</span> <span class="o">=</span> <span class="n">Mock</span><span class="p">()</span>
</pre></div>
</div>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p><tt class="docutils literal"><span class="pre">&#64;patch</span></tt> decorations are evaluated at compile-time, so a
workaround like this does <strong>not</strong> work:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">TestFileBacked</span><span class="p">(</span><span class="n">Bcfg2TestCase</span><span class="p">):</span>
    <span class="nd">@patch</span><span class="p">(</span><span class="s">&quot;</span><span class="si">%s</span><span class="s">.open&quot;</span> <span class="o">%</span> <span class="n">builtins</span><span class="p">)</span>
    <span class="nd">@patch</span><span class="p">(</span><span class="s">&quot;</span><span class="si">%s</span><span class="s">.</span><span class="si">%s</span><span class="s">.Index&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">test_obj</span><span class="o">.</span><span class="n">__module__</span><span class="p">,</span>
                            <span class="bp">self</span><span class="o">.</span><span class="n">test_obj</span><span class="o">.</span><span class="n">__name</span><span class="p">))</span>
    <span class="k">def</span> <span class="nf">test_HandleEvent</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">mock_Index</span><span class="p">,</span> <span class="n">mock_open</span><span class="p">):</span>
        <span class="o">...</span>
</pre></div>
</div>
<p class="last">But see below about patching objects before instantiation.</p>
</div>
<p>In some cases, you will need to patch an object in order to
instantiate it.  For instance, consider
<a class="reference internal" href="plugins.html#Bcfg2.Server.Plugin.helpers.DirectoryBacked" title="Bcfg2.Server.Plugin.helpers.DirectoryBacked"><tt class="xref py py-class docutils literal"><span class="pre">Bcfg2.Server.Plugin.helpers.DirectoryBacked</span></tt></a>, which attempts
to set a file access monitor watch when it is instantiated.  This
won&#8217;t work during unit testing, so we have to patch
<a class="reference internal" href="plugins.html#Bcfg2.Server.Plugin.helpers.DirectoryBacked.add_directory_monitor" title="Bcfg2.Server.Plugin.helpers.DirectoryBacked.add_directory_monitor"><tt class="xref py py-func docutils literal"><span class="pre">Bcfg2.Server.Plugin.helpers.DirectoryBacked.add_directory_monitor()</span></tt></a>
in order to successfully instantiate a <tt class="docutils literal"><span class="pre">DirectoryBacked</span></tt> object.  In
order to do that, we need to patch the object being tested, which is a
variable, but we need to evaluate the patch at run-time, not at
compile time, in order to deal with inheritance.  This can be done
with a <tt class="docutils literal"><span class="pre">&#64;patch</span></tt> decorator on an inner function, e.g.:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="k">class</span> <span class="nc">TestDirectoryBacked</span><span class="p">(</span><span class="n">Bcfg2TestCase</span><span class="p">):</span>
    <span class="n">test_obj</span> <span class="o">=</span> <span class="n">DirectoryBacked</span>

    <span class="k">def</span> <span class="nf">test__init</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="nd">@patch</span><span class="p">(</span><span class="s">&quot;</span><span class="si">%s</span><span class="s">.</span><span class="si">%s</span><span class="s">.add_directory_monitor&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">test_obj</span><span class="o">.</span><span class="n">__module__</span><span class="p">,</span>
                                                <span class="bp">self</span><span class="o">.</span><span class="n">test_obj</span><span class="o">.</span><span class="n">__name__</span><span class="p">))</span>
        <span class="k">def</span> <span class="nf">inner</span><span class="p">(</span><span class="n">mock_add_monitor</span><span class="p">):</span>
            <span class="n">db</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">test_obj</span><span class="p">(</span><span class="n">datastore</span><span class="p">,</span> <span class="n">Mock</span><span class="p">())</span>
            <span class="n">mock_add_monitor</span><span class="o">.</span><span class="n">assert_called_with</span><span class="p">(</span><span class="s">&#39;&#39;</span><span class="p">)</span>

        <span class="n">inner</span><span class="p">()</span>
</pre></div>
</div>
<p><tt class="docutils literal"><span class="pre">inner()</span></tt> is patched when <tt class="docutils literal"><span class="pre">test__init()</span></tt> is called, and so
<tt class="docutils literal"><span class="pre">&#64;patch()</span></tt> is called with the module and the name of the object
being tested as defined by the test object (i.e., not as defined by
the parent object).  If this is not done, then the patch will be
applied at compile-time and <tt class="docutils literal"><span class="pre">add_directory_monitor</span></tt> will be patched
on the <tt class="docutils literal"><span class="pre">DirectoryBacked</span></tt> class instead of on the class to be tested.</p>
<p>Some of our older unit tests do not follow these rules religiously, so
as more tests are written that inherit from larger portions of the
<tt class="docutils literal"><span class="pre">testsuite</span></tt> tree they may need to be refactored.</p>
</div>
<div class="section" id="naming">
<h3>Naming<a class="headerlink" href="#naming" title="Permalink to this headline">¶</a></h3>
<p>In order to make the system of inheritance we implement possible, we
must follow these naming conventions fairly religiously.</p>
<ul class="simple">
<li>Test classes are given the name of the object to be tested with
<tt class="docutils literal"><span class="pre">Test</span></tt> prepended.  E.g., the test for the
<tt class="xref py py-class docutils literal"><span class="pre">Bcfg2.Server.Plugins.Metadata.Metadata</span></tt> is named
<tt class="docutils literal"><span class="pre">TestMetadata</span></tt>.</li>
<li>Test classes that test miscellaneous functions in a module are named
<tt class="docutils literal"><span class="pre">TestFunctions</span></tt>.</li>
<li>Test modules are given the name of the module to be tested with
<tt class="docutils literal"><span class="pre">Test</span></tt> prepended.  Tests for <tt class="docutils literal"><span class="pre">__init__.py</span></tt> are named
<tt class="docutils literal"><span class="pre">Test_init.py</span></tt> (one underscore).</li>
<li>Tests for methods or functions are given the name of the method or
function to be tested with <tt class="docutils literal"><span class="pre">test_</span></tt> prepended.  E.g., the test for
<a class="reference internal" href="plugins.html#Bcfg2.Server.Plugin.helpers.StructFile.Match" title="Bcfg2.Server.Plugin.helpers.StructFile.Match"><tt class="xref py py-class docutils literal"><span class="pre">Bcfg2.Server.Plugin.helpers.StructFile.Match</span></tt></a> is called
<tt class="docutils literal"><span class="pre">test_Match</span></tt>; the test for
<tt class="xref py py-class docutils literal"><span class="pre">Bcfg2.Server.Plugin.helpers.StructFile._match</span></tt> is called
<tt class="docutils literal"><span class="pre">test__match</span></tt>.</li>
<li>Tests for magic methods &#8211; those that start and end with double
underscores &#8211; are named <tt class="docutils literal"><span class="pre">test__&lt;name&gt;</span></tt>, where name is the name of
the magic method without underscores.  E.g., a test for <tt class="docutils literal"><span class="pre">__init__</span></tt>
is called <tt class="docutils literal"><span class="pre">test__init</span></tt>, and a test for <tt class="docutils literal"><span class="pre">__getitem__</span></tt> is called
<tt class="docutils literal"><span class="pre">test__getitem</span></tt>. If this causes a collision with a non-magic
function (e.g., if a class also has a function called
<tt class="docutils literal"><span class="pre">_getitem()</span></tt>, the test for which would also be called
<tt class="docutils literal"><span class="pre">test__getitem</span></tt>, seriously consider refactoring the code for the
class.</li>
</ul>
</div>
<div class="section" id="common-test-code">
<h3>Common Test Code<a class="headerlink" href="#common-test-code" title="Permalink to this headline">¶</a></h3>
</div>
</div>
</div>


          </div>
        </div>
      </div>
      <div class="sphinxsidebar">
        <div class="sphinxsidebarwrapper">
  <h3><a href="../index.html">Table Of Contents</a></h3>
  <ul>
<li><a class="reference internal" href="#">Bcfg2 unit testing</a><ul>
<li><a class="reference internal" href="#testing-in-a-virtualenv">Testing in a virtualenv</a></li>
<li><a class="reference internal" href="#writing-unit-tests">Writing Unit Tests</a><ul>
<li><a class="reference internal" href="#inherit-tests">Inherit Tests</a></li>
<li><a class="reference internal" href="#relative-imports">Relative Imports</a></li>
<li><a class="reference internal" href="#avoid-patching-where-possible">Avoid Patching Where Possible</a></li>
<li><a class="reference internal" href="#naming">Naming</a></li>
<li><a class="reference internal" href="#common-test-code">Common Test Code</a></li>
</ul>
</li>
</ul>
</li>
</ul>

  <h4>Previous topic</h4>
  <p class="topless"><a href="tips.html"
                        title="previous chapter">Tips for Bcfg2 Development</a></p>
  <h4>Next topic</h4>
  <p class="topless"><a href="versioning.html"
                        title="next chapter">Versioning Bcfg2</a></p>
  <h3>This Page</h3>
  <ul class="this-page-menu">
    <li><a href="../_sources/development/unit-testing.txt"
           rel="nofollow">Show Source</a></li>
  </ul>
<div id="searchbox" style="display: none">
  <h3>Quick search</h3>
    <form class="search" action="../search.html" method="get">
      <input type="text" name="q" />
      <input type="submit" value="Go" />
      <input type="hidden" name="check_keywords" value="yes" />
      <input type="hidden" name="area" value="default" />
    </form>
    <p class="searchtip" style="font-size: 90%">
    Enter search terms or a module, class or function name.
    </p>
</div>
<script type="text/javascript">$('#searchbox').show(0);</script>
        </div>
      </div>
      <div class="clearer"></div>
    </div>
    <div class="related">
      <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="versioning.html" title="Versioning Bcfg2"
             >next</a> |</li>
        <li class="right" >
          <a href="tips.html" title="Tips for Bcfg2 Development"
             >previous</a> |</li>
	<li><a href="../index.html">home</a> |&nbsp;</li>
	<!--<li><a href="../search.html">search</a> |&nbsp;</li>-->
	<li><a href="../help/index.html">help</a> |&nbsp;</li>
	<li><a href="../contents.html">documentation </a> &raquo;</li>

          <li><a href="../contents.html" >Bcfg2 documentation 1.3.0</a> &raquo;</li>
          <li><a href="index.html" >Bcfg2 Development</a> &raquo;</li> 
      </ul>
    </div>
    <div class="footer">
        &copy; Copyright 2009-2013, Narayan Desai.
      Last updated on Mar 20, 2013.
      Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
    </div>
  </body>
</html>