2

I'm curating a large number of unit tests for a large Python project. We use nose to do our test discovery and execution. I have some test files that really shouldn't be run in certain conditions. For instance, maybe I have a test module that should never be run on Windows (only on Mac and Linux).

Here are some solutions I have used:

  1. Mark test methods or classes with conditions using Nose's excellent attrib plugin.
  2. Use unittest.skipIf() on test methods or classes
  3. Use nose's pattern exclusions to skip files with windows in the name, for instance.

My complaint about 1 & 2 is that these force me to import the module, which is at least a waste of time and could possibly cause errors if there are platform dependent imports. I don't like #3 because I feel like it is brittle, and not easily apparent when reading the test case that it will be skipped. All three seem to depend excessively on the interaction between the test and the test runner, I'd like something that is just in the test.

I would like to do something like the following at the top of the test module:

"""This module should not be run on Windows"""
import platform
if platform.system() == 'Windows':
    <stop reading this module.  nothing to see here>

# do the tests.

How can I tell Python or Nose to stop reading the module, but that there is no error? I guess I am looking for the import equivalent of an early return.

dbn
  • 13,144
  • 3
  • 60
  • 86
  • You could do it by raising an exception, but you would have to catch that in the client code. – wim Feb 23 '13 at 01:49
  • If your main issue is "importing is a waste of time", then I wouldn't worry about it too much. Python imports 30-40 modules just to start the interpreter (see: python -vv), and running projects that import 100s or 1000s isn't going to slow you down. Besides, even on a huge project, the amount of platform-specific test code should be pretty small. How many modules are we talking about? – Seth Feb 23 '13 at 02:18
  • Definitely talking about 1000s, but some of them are slow imports because of poor design. However, the main issue is that these imports fail, creating false negatives in our test logs. – dbn Feb 23 '13 at 02:21
  • Just to clarify - this is not just platform specific, some of it is stuff like "opengl isn't available" or "third party tool isn't licensed." – dbn Feb 23 '13 at 02:22

3 Answers3

2

The ability to return early from the execution of a module has been proposed before but it received some negative votes and the feature was not added to the language.

You can read the mailing list thread, but generally it was not felt that the problem of having to indent large parts of a module by an extra level was not a good enough reason to add this "return" feature. Some said that almost all code in modules should be inside functions and classes anyway, leaving almost no module-level code that would be subject to this problem.

Celada
  • 21,627
  • 4
  • 64
  • 78
2

Under Nose and unittest, the SkipTest exception is treated specially - it's not a failure. Thus, the following code will stop execution, and no error will be reported to the unittest runner:

import unittest
import platform
if platform.system() == 'Windows':
  raise unittest.case.SkipTest("The rest of this code will not be run on Windows.")
dbn
  • 13,144
  • 3
  • 60
  • 86
1

You can raise ImportError there with that message. The caller will likely exit with an uncaught exception explaining showing that error, but it can catch the ImportError if necessary.

Keith
  • 42,110
  • 11
  • 57
  • 76