<!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". 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 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 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>
import module<br>
except ImportError:<br>
module = None<br>
<br>
class SomeTest(unittest2.TestCase):<br>
@unittest2.skipIf(module is None, "Test requires module")<br>
def test_something(self):<br>
...<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>