<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <meta content="text/html; charset=ISO-8859-1"
      http-equiv="Content-Type">
  </head>
  <body bgcolor="#ffffff" text="#000000">
    On 03/01/2011 17:13, Manuel de la Pena Saenz wrote:
    <blockquote
      cite="mid:4ECD0DF7-EC3B-4475-8365-A30BD6BE6087@canonical.com"
      type="cite">Hello *,
      <div><br>
      </div>
      <div>At the moment I'm working on the port to Windows of some code
        that was initially written to work only on Linux (desktopcouch).
        To make the port easier, I'm currently working on ensuring that
        the tests that were written can be ran on Windows. This has lead
        me to a problem I really do not know how to solve:</div>
      <div><br>
      </div>
      <div>Desktopcouch uses dbus to advertise the port in which the
        users personal CouchDb is running. A certain amount of our tests
        are integration tests that require dbus to be running. As you
        can imaging this tests fail on Windows but should not be
        considered to be a fail since it is "an expected fail".&nbsp;To load
        an run or test I use u1trial, which can be found in Launchpad (<a
          moz-do-not-send="true"
          href="http://launchpad.net/ubuntuone-dev-tools">launchpad.net/ubuntuone-dev-tools</a>)
        to which I am adding an @skip decorator (and similar) to work
        with twisted.trial.unittest.TestCase so that we can skip tests
        (the code can be found at
        at&nbsp;lp:~mandel/ubuntuone-dev-tools/load_test_according_to_platform
        in testcase.py). The @skipIf approach works on those tests that
        do not have imports which cannot be found on Windows (for
        example, it does not have import dbus), however if the imports
        are present when loading the test we have an import error and we
        never get the SkipTest exception. This ImportErrors of course
        occur due to the fact that u1trial &nbsp;uses __import__ to load the
        test cases and the module to load has an "platform illegal
        import"</div>
      <div><br>
      </div>
    </blockquote>
    <br>
    I solve this problem like this:<br>
    <br>
    import unittest2<br>
    try:<br>
    &nbsp;&nbsp;&nbsp; import module<br>
    except ImportError:<br>
    &nbsp;&nbsp;&nbsp; module = None<br>
    <br>
    class SomeTest(unittest2.TestCase):<br>
    &nbsp;&nbsp;&nbsp; @unittest2.skipIf(module is None, "Test requires module")<br>
    &nbsp;&nbsp;&nbsp; def test_something(self):<br>
    &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ...<br>
    <br>
    The skip decorators can be applied to a whole class as well as
    methods from Python 2.6.<br>
    <br>
    An alternative approach:<br>
    <br>
    <pre><span class="k">try</span><span class="p">:</span>
  <span class="kn">import</span> <span class="nn">somemodule</span>
<span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
  <span class="n">somemodule</span> <span class="o">=</span> <span class="bp">None</span>


def error_if_missing(name):
  failed = False
  try:
    __import__(name)
  except:
    failed = True
  <span class="k">def</span> <span class="nf">decorator</span><span class="p">(</span><span class="n">f</span><span class="p">):</span>
  <span class="k">  def</span> <span class="nf">inner</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    <span class="k">  if</span> <span class="n">failed</span><span class="bp"></span><span class="p">:</span>
      <span class="k">  raise</span> <span class="ne">ImportError</span><span class="p">(</span><span class="s">'name'</span><span class="p">)</span>
    <span class="k">  return</span> <span class="n">f</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
  <span class="k">  return</span> <span class="n">inner</span>
  return decorator

<span class="k">class</span> <span class="nc">SomeTest</span><span class="p">(</span><span class="n">unittest2</span><span class="o">.</span><span class="n">TestCase</span><span class="p">):</span>

  <span class="nd">@error_if_missing</span>('<span class="nn">somemodule</span>')
  <span class="k">def</span> <span class="nf">test_something2</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
    ...

I dislike the "auto-adding to module globals" approach as it means a core part of the setup is done behind the scenes and invisible.
</pre>
    All the best,<br>
    <br>
    Michael Foord<br>
    <br>
    <br>
    <blockquote
      cite="mid:4ECD0DF7-EC3B-4475-8365-A30BD6BE6087@canonical.com"
      type="cite">
      <div>My first attempt to solve this situation has been to write a
        decorator that will skip a test case if one of its imports fails
        and if they do not fail, it will add the modules to the
        func_globals of the test. The code of such an attempt is the
        following:</div>
      <div><br>
      </div>
      <div><span class="Apple-style-span" style="font-family:
          Verdana,arial,helvetica,sans-serif;">
          <pre><span class="k" style="color: rgb(170, 34, 255); font-weight: bold;">def</span> <span class="nf" style="color: rgb(0, 160, 0);">skipIfNotModules</span><span class="p">(</span><span class="n">modules</span><span class="p">,</span> <span class="n">reason</span><span class="p">):</span>
    <span class="sd" style="color: rgb(187, 68, 68); font-style: italic;">"""</span>
<span class="sd" style="color: rgb(187, 68, 68); font-style: italic;">    Skip tests when a set of modules is missing.</span>
<span class="sd" style="color: rgb(187, 68, 68); font-style: italic;">    """</span>
    <span class="k" style="color: rgb(170, 34, 255); font-weight: bold;">if</span> <span class="n">modules</span><span class="p">:</span>
        <span class="k" style="color: rgb(170, 34, 255); font-weight: bold;">def</span> <span class="nf" style="color: rgb(0, 160, 0);">decorator</span><span class="p">(</span><span class="n">test_item</span><span class="p">):</span>
            <span class="k" style="color: rgb(170, 34, 255); font-weight: bold;">if</span> <span class="ow" style="color: rgb(170, 34, 255); font-weight: bold;">not</span> <span class="p">(</span><span class="nb" style="color: rgb(170, 34, 255);">isinstance</span><span class="p">(</span><span class="n">test_item</span><span class="p">,</span> <span class="nb" style="color: rgb(170, 34, 255);">type</span><span class="p">)</span> <span class="ow" style="color: rgb(170, 34, 255); font-weight: bold;">and</span>\
                <span class="nb" style="color: rgb(170, 34, 255);">issubclass</span><span class="p">(</span><span class="n">test_item</span><span class="p">,</span> <span class="n">TestCase</span><span class="p">)):</span>
                <span class="k" style="color: rgb(170, 34, 255); font-weight: bold;">def</span> <span class="nf" style="color: rgb(0, 160, 0);">decorator</span><span class="p">(</span><span class="n">test_item</span><span class="p">):</span>
                    <span class="nd" style="color: rgb(170, 34, 255);">@wraps</span><span class="p">(</span><span class="n">test_item</span><span class="p">)</span>
                    <span class="k" style="color: rgb(170, 34, 255); font-weight: bold;">def</span> <span class="nf" style="color: rgb(0, 160, 0);">import_wrapper</span><span class="p">(</span><span class="o" style="color: rgb(102, 102, 102);">*</span><span class="n">args</span><span class="p">,</span> <span class="o" style="color: rgb(102, 102, 102);">**</span><span class="n">kwargs</span><span class="p">):</span>
                        <span class="k" style="color: rgb(170, 34, 255); font-weight: bold;">for</span> <span class="n">module_to_import</span> <span class="ow" style="color: rgb(170, 34, 255); font-weight: bold;">in</span> <span class="n">modules</span><span class="p">:</span>
                            <span class="k" style="color: rgb(170, 34, 255); font-weight: bold;">try</span><span class="p">:</span>
                                <span class="n">test_item</span><span class="o" style="color: rgb(102, 102, 102);">.</span><span class="n">func_globals</span><span class="p">[</span><span class="n">module_to_import</span><span class="p">]</span> <span class="o" style="color: rgb(102, 102, 102);">=</span> <span class="nb" style="color: rgb(170, 34, 255);">__import__</span><span class="p">(</span><span class="n">module_to_import</span><span class="p">)</span>
                            <span class="k" style="color: rgb(170, 34, 255); font-weight: bold;">except</span> <span class="ne" style="color: rgb(210, 65, 58); font-weight: bold;">ImportError</span><span class="p">:</span>
                                <span class="k" style="color: rgb(170, 34, 255); font-weight: bold;">raise</span> <span class="n">SkipTest</span><span class="p">(</span><span class="n">reason</span><span class="p">)</span>
                            <span class="k" style="color: rgb(170, 34, 255); font-weight: bold;">return</span> <span class="n">test_item</span><span class="p">(</span><span class="o" style="color: rgb(102, 102, 102);">*</span><span class="n">args</span><span class="p">,</span> <span class="o" style="color: rgb(102, 102, 102);">**</span><span class="n">kwargs</span><span class="p">)</span>
                            <span class="n">test_item</span> <span class="o" style="color: rgb(102, 102, 102);">=</span> <span class="n">import_wrapper</span>
                            <span class="k" style="color: rgb(170, 34, 255); font-weight: bold;">return</span> <span class="n">test_item</span>
                    <span class="k" style="color: rgb(170, 34, 255); font-weight: bold;">return</span> <span class="n">decorator</span>
            <span class="c" style="color: rgb(0, 136, 0); font-style: italic;"># tell twisted.trial.unittest to skip the test, pylint will </span>
            <span class="c" style="color: rgb(0, 136, 0); font-style: italic;"># complain since it thinks we are redefining a name out </span>
            <span class="c" style="color: rgb(0, 136, 0); font-style: italic;"># of the scope</span>
            <span class="c" style="color: rgb(0, 136, 0); font-style: italic;"># pylint: disable=W0621,W0612</span>
            <span class="n">test_item</span><span class="o" style="color: rgb(102, 102, 102);">.</span><span class="n">skip</span> <span class="o" style="color: rgb(102, 102, 102);">=</span> <span class="n">reason</span>
            <span class="c" style="color: rgb(0, 136, 0); font-style: italic;"># pylint: enable=W0621,W0612</span>
            <span class="c" style="color: rgb(0, 136, 0); font-style: italic;"># because the item was skipped, we will make sure that no</span>
            <span class="c" style="color: rgb(0, 136, 0); font-style: italic;"># services are started for it</span>
            <span class="k" style="color: rgb(170, 34, 255); font-weight: bold;">if</span> <span class="nb" style="color: rgb(170, 34, 255);">hasattr</span><span class="p">(</span><span class="n">test_item</span><span class="p">,</span> <span class="s" style="color: rgb(187, 68, 68);">"required_services"</span><span class="p">):</span>
                <span class="c" style="color: rgb(0, 136, 0); font-style: italic;"># pylint: disable=W0612</span>
                <span class="n">test_item</span><span class="o" style="color: rgb(102, 102, 102);">.</span><span class="n">required_services</span> <span class="o" style="color: rgb(102, 102, 102);">=</span> <span class="k" style="color: rgb(170, 34, 255); font-weight: bold;">lambda</span> <span class="o" style="color: rgb(102, 102, 102);">*</span><span class="n">args</span><span class="p">,</span> <span class="o" style="color: rgb(102, 102, 102);">**</span><span class="n">kwargs</span><span class="p">:</span> <span class="p">[]</span>
                <span class="c" style="color: rgb(0, 136, 0); font-style: italic;"># pylint: enable=W0612</span>
            <span class="k" style="color: rgb(170, 34, 255); font-weight: bold;">return</span> <span class="n">test_item</span>
        <span class="k" style="color: rgb(170, 34, 255); font-weight: bold;">return</span> <span class="n">decorator</span>
    <span class="k" style="color: rgb(170, 34, 255); font-weight: bold;">return</span> <span class="n">_id</span></pre>
        </span>
        <div>While the above code works for a test method, it does not
          for a TestCase. I was wondering if someone in the list has
          experience with this type of situation in which tests have to
          be skipped when the are loaded by a test runner like u1trial
          depending on the platform. I am specially interested in those
          examples where the information of which test to be run does
          not have to be supplied to the test loader in an "artificial
          way" (I consider to be an artificial way to pass a dict with
          the os.platform as the keys and the value a list of the test
          to run).</div>
      </div>
      <div><br>
      </div>
      <div>I would greatly appreciate any input in this particular
        problem as well as to the more general question of, how do I
        plan my tests so that we can work in a multi-platform env?</div>
      <pre wrap="">
<fieldset class="mimeAttachmentHeader"></fieldset>
_______________________________________________
testing-in-python mailing list
<a class="moz-txt-link-abbreviated" href="mailto:testing-in-python@lists.idyll.org">testing-in-python@lists.idyll.org</a>
<a class="moz-txt-link-freetext" href="http://lists.idyll.org/listinfo/testing-in-python">http://lists.idyll.org/listinfo/testing-in-python</a>
</pre>
    </blockquote>
    <br>
    <br>
    <pre class="moz-signature" cols="72">-- 
<a class="moz-txt-link-freetext" href="http://www.voidspace.org.uk/">http://www.voidspace.org.uk/</a>

May you do good and not evil
May you find forgiveness for yourself and forgive others
May you share freely, never taking more than you give.
-- the sqlite blessing <a class="moz-txt-link-freetext" href="http://www.sqlite.org/different.html">http://www.sqlite.org/different.html</a>
</pre>
  </body>
</html>