<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">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 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><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; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; "><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></body></html>