Changeset 18
- Timestamp:
- Sun Apr 2 22:26:13 2006
- Files:
-
- trunk/nose/core.py (modified) (diff)
- trunk/nose/suite.py (modified) (diff)
- trunk/nose/plugins/base.py (modified) (diff)
- trunk/nose/plugins/__init__.py (modified) (diff)
- trunk/nose/plugins/missed.py (added)
- trunk/nose/util.py (modified) (diff)
- trunk/nose/result.py (modified) (diff)
- trunk/nose/selector.py (modified) (diff)
- trunk/nose/loader.py (modified) (diff)
- trunk/st/unit_tests/test_selector.py (modified) (diff)
- trunk/st/unit_tests/test_utils.py (modified) (diff)
- trunk/st/unit_tests/test_plugins.py (modified) (diff)
- trunk/st/unit_tests/support/foo/tests (added)
- trunk/st/unit_tests/support/foo/tests/dir_test_file.py (added)
- trunk/st/unit_tests/test_loader.py (modified) (diff)
- trunk/setup.py (modified) (diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
trunk/nose/core.py
r15 r18 144 144 145 145 # FIXME is this the same signature as unittest? 146 # FIXME no it is not. fix this! 146 147 def __init__(self, argv=None, env=None, testRunner=None, 147 148 testCollector=defaultTestCollector, stream=sys.stderr): … … 316 317 317 318 def configure_logging(options): 318 loggers = [ '', 'nose', 'nose.core', 'nose.importer', 'nose.inspector', 319 'nose.loader', 'nose.plugins', 'nose.result', 319 loggers = [ '', 'nose', 'nose.case', 'nose.core', 'nose.importer', 320 'nose.inspector', 'nose.loader', 'nose.plugins', 'nose.result', 320 321 'nose.selector', 'nose.suite' ] 322 323 # output 324 if options.debug_log: 325 format = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') 326 handler = logging.FileHandler(options.debug_log) 327 handler.setFormatter(format) 328 logging.getLogger('').addHandler(handler) 329 else: 330 logging.basicConfig() 331 321 332 lvl = logging.WARNING 322 333 if options.verbosity >= 5: … … 329 340 l = logging.getLogger(logger) 330 341 l.setLevel(lvl) 331 342 331 342 # individual overrides 332 343 if options.debug: … … 337 348 l.setLevel(logging.DEBUG) 338 349 339 # output 340 if options.debug_log: 341 format = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') 342 handler = logging.FileHandler(options.debug_log) 343 handler.setFormatter(format) 344 logging.getLogger('').addHandler(handler) 345 else: 346 logging.basicConfig() 347 348 350 349 351 def main(*arg, **kw): 350 352 """Collect and run test, returning success or failure -
trunk/nose/suite.py
r15 r18 10 10 class LazySuite(unittest.TestSuite): 11 11 12 # _exc_info_to_string needs this propery 12 # _exc_info_to_string needs this property 12 12 failureException = unittest.TestCase.failureException 13 13 -
trunk/nose/plugins/base.py
r17 r18 4 4 5 5 class Plugin(object): 6 """Base class for nose plugins. It's not necessaryto subclass this6 """Base class for nose plugins. It's not *necessary* to subclass this 6 6 class to create a plugin; however, all plugins must implement 7 7 `add_options(self, parser, env)` and `configure(self, options, … … 86 86 87 87 While it is recommended that plugins subclass 88 nose.plugins. base.Plugin, the only requirements for a plugin are88 nose.plugins.Plugin, the only requirements for a plugin are 88 88 that it implement the methods `add_options(self, parser, env)` and 89 89 `configure(self, options, conf)`, and have the attributes … … 96 96 97 97 When plugins are called, the first plugin that implements a method 98 and returns a non-None value wins, and plugin processing ends. 98 and returns a non-None value wins, and plugin processing ends. The 99 only exceptions to are `loadTestsFromModule`, `loadTestsFromName`, 100 and `loadTestsFromPath`, which allow multiple plugins to load tests. 99 101 100 102 In general, plugin methods correspond directly to the methods of … … 279 281 280 282 def prepareTest(self, test): 281 """Called before a test is run. If you return a non-None value, 283 """Called before the test is run by the test runner. Please note 284 the article *the* in the previous sentence: prepareTest is 285 called *only once*, and is passed the test case or test suite 286 that the test runner will execute. It is *not* called for each 287 individual test case. If you return a non-None value, 282 288 that return value will be run as the test. Use this hook to wrap 283 or decorate t ests with other functions.289 or decorate the test with another function. 283 289 284 290 Parameters: … … 291 297 def report(self, stream): 292 298 """Called after all error output has been printed. Print your 293 plugin's report to the provided stream. 299 plugin's report to the provided stream. Return None to allow 300 other plugins to print reports, any other value to stop them. 294 301 295 302 Parameters: … … 311 318 312 319 def startTest(self, test): 313 """Called before each test is run. 320 """Called before each test is run. DO NOT return a value unless 321 you want to stop other plugins from seeing the test start. 314 322 315 323 Parameters: … … 320 328 321 329 def stopTest(self, test): 322 """Called after each test is run. 330 """Called after each test is run. DO NOT return a value unless 331 you want to stop other plugins from seeing that the test has stopped. 323 332 324 333 Parameters: -
trunk/nose/plugins/__init__.py
r9 r18 7 7 --------------- 8 8 9 Plugin classes should subclass nose.plugins.Plugin or one of the other 10 classes in nose.plugins.base. 9 Plugin classes should subclass nose.plugins.Plugin. 11 10 12 Plugins may implement any of the methods in any or all of the interfaces 13 described in nose.plugins.base. 11 Plugins may implement any of the methods described in the class 12 PluginInterface in nose.plugins.base. Please note that this class is for 13 documentary purposes only; plugins may not subclass PluginInterface. 14 14 15 15 Registering … … 46 46 logging 47 47 48 Recipes 49 ======= 50 51 * Writing a plugin that monitors or controls test result output 52 53 Implement any or all of addError, addFailure, etc., to monitor test 54 results. If you also want to monitor output, implement 55 setOutputStream and keep a reference to the output stream. If you 56 want to prevent the builtin TextTestResult output, implement 57 setOutputSteam and return a dummy stream and send your desired output 58 to the real stream. 59 60 Example: examples/html_plugin/htmlplug.py 61 62 * Writing a plugin that loads tests from files other than python modules 63 64 Implement wantFile and loadTestsFromPath. In wantFile, return True 65 for files that you want to examine for tests. In loadTestsFromPath, 66 for those files, return a TestSuite or other iterable containing 67 TestCases. loadTestsFromPath may also be a generator. 68 69 Example: nose.plugins.doctests 70 71 * Writing a plugin that prints a report 72 73 Implement begin if you need to perform setup before testing 74 begins. Implement report and output your report to the provided stream. 75 76 Examples: nose.plugins.cover, nose.plugins.profile, nose.plugins.missed 77 78 * Writing a plugin that selects or rejects tests 79 80 Implement any or all want* methods. Return False to reject the test 81 candidate, True to accept it -- which means that the test candidate 82 will pass through the rest of the system, so you must be prepared to 83 load tests from it if tests can't be loaded by the core loader or 84 another plugin -- and None if you don't care. 85 86 Examples: nose.plugins.attrib, nose.plugins.doctests 87 48 88 Examples 49 89 ======== -
trunk/nose/util.py
r15 r18 6 6 import sys 7 7 import types 8 import unittest 8 9 9 10 log = logging.getLogger('nose') … … 101 102 return (cls_adr[0], cls_adr[1], 102 103 "%s.%s" % (cls_adr[2], test.__name__)) 104 # handle unittest.TestCase instances 105 if isinstance(test, unittest.TestCase): 106 if hasattr(test, 'testFunc'): 107 # nose FunctionTestCase 108 return test_address(test.testFunc) 109 if hasattr(test, '_FunctionTestCase__testFunc'): 110 # unittest FunctionTestCase 111 return test_address(test._FunctionTestCase__testFunc) 112 if hasattr(test, 'testCase'): 113 # nose MethodTestCase 114 return test_address(test.testCase) 115 # regular unittest.TestCase 116 cls_adr = test_address(test.__class__) 117 return (cls_adr[0], cls_adr[1], 118 "%s.%s" % (cls_adr[2], test._TestCase__testMethodName)) 103 119 raise TypeError("I don't know what %s is (%s)" % (test, t)) 104 120 -
trunk/nose/result.py
r17 r18 39 39 whole to be considered non-successful. 40 40 """ 41 separator3 = '.' * 7042 41 43 42 def __init__(self, stream, descriptions, verbosity, conf): -
trunk/nose/selector.py
r14 r18 28 28 """ 29 29 if not self.tests: 30 return None 31 failed = False 32 for test in self.tests: 33 filename, modname, funcname = split_test_name(test) 34 res = func(filename, modname, funcname) 35 if res: 36 # a match 37 return True 38 elif res is False: 39 # a direct miss 40 failed = True 41 return not failed 30 log.debug("No tests to check") 31 return True 32 33 log.debug('tests to check: %s', self.tests) 34 matches = [ func(*test_tuple) for test_tuple in 35 map(split_test_name, self.tests) ] 36 return filter(lambda x: x is not False, matches) 42 37 43 38 def callableInTests(self, clb, matches): … … 58 53 containerMatch = True 59 54 if modname is not None and not containerMatch: 60 if clb.__module__.startswith(modname): 61 containerMatch = True 55 try: 56 log.debug("Check container match: %s v %s", 57 clb.__module__, modname) 58 if clb.__module__.startswith(modname): 59 containerMatch = True 60 except AttributeError: 61 # some kind of weird attribute; this can't be a test 62 return False 62 63 if ((filename is not None or modname is not None) 63 64 and not containerMatch): … … 84 85 self.match = conf.testMatch 85 86 self.tests = conf.tests 86 87 86 87 def fileInTests(self, file): 87 88 def match(filename, modname, funcname, file=file): … … 116 117 def moduleInTests(self, module, either=False): 117 118 def match(filename, modname, funcname, module=module, either=either): 119 log.debug("Checking module %s in test %s:%s (either: %s)", 120 module.__name__, modname, funcname, either) 118 121 if modname is None: 119 122 return None 120 123 mname = module.__name__ 121 return (mname.startswith(modname) 122 or (either and modname.startswith(mname))) 123 return self.anytest(match) 124 124 result = (mname.startswith(modname) 125 or (either and modname.startswith(mname))) 126 log.debug("Module %s match %s (either: %s) result %s", 127 module.__name__, modname, either, result) 128 return result 129 res = self.anytest(match) 130 log.debug("Module %s in tests result: %s", module.__name__, res) 131 return res 125 132 126 133 def wantClass(self, cls): … … 133 140 self.tests: 134 141 """ 142 log.debug("Load tests from class %s?", cls) 143 135 144 wanted = (not cls.__name__.startswith('_') 136 145 and (issubclass(cls, unittest.TestCase) 137 146 or self.match.search(cls.__name__))) 138 plug_wants = call_plugins(self.plugins, 'wantClass', cls) 147 log.debug("%s is wanted? %s", cls, wanted) 148 plug_wants = call_plugins(self.plugins, 'wantClass', cls) 139 149 if plug_wants is not None: 150 log.debug("Plugin setting selection of %s to %s", cls, plug_wants) 140 151 wanted = plug_wants 141 return wanted and (self.classInTests(cls) is not False)152 return wanted and self.classInTests(cls) 141 152 142 153 def wantDirectory(self, dirname): … … 175 186 files. 176 187 """ 188 in_tests = self.fileInTests(file) 189 if not in_tests: 190 return False 191 177 192 base = os.path.basename(file) 178 193 root, ext = os.path.splitext(base) … … 187 202 if plug_wants is not None: 188 203 wanted = plug_wants 189 return wanted and (self.fileInTests(file) is not False)204 return wanted or (pysrc and self.tests and in_tests) 189 204 190 205 def wantFunction(self, function): … … 201 216 # not a function 202 217 return False 218 in_tests = self.funcInTests(function) 219 if not in_tests: 220 return False 203 221 wanted = not funcname.startswith('_') and self.matches(funcname) 204 222 plug_wants = call_plugins(self.plugins, 'wantFunction', function) 205 223 if plug_wants is not None: 206 224 wanted = plug_wants 207 return wanted and (self.funcInTests(function) is not False)225 return wanted 207 225 208 226 def wantMethod(self, method): … … 219 237 # not a method 220 238 return False 221 wanted = (not method_name.startswith('_') 222 and self.matches(method_name)) 239 if method_name.startswith('_'): 240 # never collect 'private' methods 241 return False 242 in_tests = self.methodInTests(method) 243 if not in_tests: 244 return False 245 wanted = self.matches(method_name) 223 246 plug_wants = call_plugins(self.plugins, 'wantMethod', method) 224 247 if plug_wants is not None: 225 248 wanted = plug_wants 226 return wanted and (self.methodInTests(method) is not False)249 return wanted 226 249 227 250 def wantModule(self, module): … … 236 259 modules where wantModuleTests() is true. 237 260 """ 238 wanted = self.matches(module.__name__.split('.')[-1])239 261 in_tests = self.moduleInTests(module, either=True) 262 if not in_tests: 263 return False 264 wanted = self.matches(module.__name__.split('.')[-1]) 240 265 plug_wants = call_plugins(self.plugins, 'wantModule', module) 241 if in_tests is False: 242 return False 243 if plug_wants is False: 244 return False 245 return wanted or in_tests or plug_wants 266 if plug_wants is not None: 267 wanted = plug_wants 268 return wanted or (self.tests and in_tests) 246 269 247 270 def wantModuleTests(self, module): … … 256 279 tests, but instead cause the standard collector to collect tests. 257 280 """ 258 281 in_tests = self.moduleInTests(module) 282 if not in_tests: 283 return False 284 259 285 # unittest compat: always load from __main__ 260 286 wanted = (self.matches(module.__name__.split('.')[-1]) 261 287 or module.__name__ == '__main__') 262 in_tests = self.moduleInTests(module) 263 plug_wants = call_plugins(self.plugins, 'wantModuleTests', module) 264 if in_tests is False: 265 return False 266 if plug_wants is False: 267 return False 268 return wanted or in_tests or plug_wants 288 plug_wants = call_plugins(self.plugins, 'wantModuleTests', 289 module) 290 if plug_wants is not None: 291 wanted = plug_wants 292 return wanted or (self.tests and in_tests) 269 293 270 294 defaultSelector = Selector -
trunk/nose/loader.py
r17 r18 68 68 for test in self.testsInModule(module, importPath): 69 69 tests.append(test) 70 70 71 # FIXME all plugins should be allowed to play 71 72 # give plugins a chance 72 73 for plug in self.conf.plugins: … … 90 91 tests.append(test) 91 92 # compat w/unittest 92 return unittest.TestSuite(tests)93 return self.suiteClass(tests) 92 93 93 94 def loadTestsFromModuleName(self, module_name, package=None, … … 104 105 yield TestModule(self.loadTestsFromModule, 105 106 self.conf, module_name, importPath) 106 107 108 # FIXME s/package/module 107 109 def loadTestsFromName(self, name, package=None, importPath=None, 108 110 module=None): … … 124 126 tests = None 125 127 path, mod_name, fn = split_test_name(name) 126 log.debug('test name % resolves to path %s, module %s, callable %s' 128 log.debug('test name %s resolves to path %s, module %s, callable %s' 126 128 % (name, path, mod_name, fn)) 127 129 if path: … … 160 162 yield test 161 163 164 # FIXME all plugins should be allowed to play 162 165 res = call_plugins(self.plugins, 'loadTestsFromName', 163 166 name, package, importPath) … … 169 172 except TypeError: 170 173 yield res 171 174 175 # FIXME s/package/module 176 # if names is a string, parse it as cmd line args 172 177 def loadTestsFromNames(self, names, package=None, module=None): 173 178 # FIXME if package is set and names is not, load from package … … 212 217 yield TestModule(self.loadTestsFromModule, 213 218 self.conf, test, importPath) 214 219 220 # FIXME all plugins should be allowed to play 215 221 # give plugins a chance 216 222 res = call_plugins(self.plugins, 'loadTestsFromPath', … … 221 227 def loadTestsFromTestCase(self, cls): 222 228 log.debug("collect tests in class %s", cls) 223 for item in dir(cls): 224 attr = getattr(cls, item) 225 wanted = False 226 if callable(attr) and self.selector.wantMethod(attr): 227 # FIXME watch for subclasses... skip base class methods 228 # unless they are overridden 229 if issubclass(cls, unittest.TestCase): 230 yield cls(item) 231 else: 232 yield MethodTestCase(cls, item) 229 collected = self.testsInTestCase(cls) 230 if self.sortTestMethodsUsing: 231 collected.sort(self.sortTestMethodsUsing) 232 233 if issubclass(cls, unittest.TestCase): 234 maketest = cls 235 else: 236 maketest = lambda i: MethodTestCase(cls, i) 237 return map(maketest, collected) 233 238 234 239 def testsInModule(self, module, importPath=None): … … 271 276 tests.extend([ FunctionTestCase(test, fromDirectory=importPath) 272 277 for test in func_tests ]) 278 log.debug("Loaded tests %s from module %s", tests, module.__name__) 273 279 return tests 274 280 281 def testsInTestCase(self, cls): 282 collected = [] 283 if cls in (object, type): 284 return collected 285 for item in dir(cls): 286 attr = getattr(cls, item) 287 log.debug("Check if selector wants %s (%s)", attr, cls) 288 if callable(attr) and self.selector.wantMethod(attr): 289 collected.append(item) 290 291 # base class methods; include those not overridden 292 for base in cls.__bases__: 293 basetests = self.testsInTestCase(base) 294 for test in basetests: 295 if not test in collected: 296 collected.append(test) 297 return collected 298 299 # FIXME this needs to be moved and generalized for methods 275 300 def generateTests(self, test): 276 301 cases = [] … … 299 324 return cases 300 325 326 # FIXME this should move to util 301 327 def isGenerator(self, test): 302 328 from compiler.consts import CO_GENERATOR -
trunk/st/unit_tests/test_selector.py
r14 r18 4 4 import nose.selector 5 5 from nose.config import Config 6 from nose.selector import Selector 6 from nose.selector import log, Selector 6 6 7 7 class Mod: … … 12 12 class TestSelector(unittest.TestCase): 13 13 14 def test_anytest(self): 15 16 def exact_file_a(filename, modname, funcname): 17 if filename is None: 18 return None 19 return filename == '/a/file.py' 20 21 def exact_file_b(filename, modname, funcname): 22 if filename is None: 23 return None 24 return filename == '/a/nother/file.py' 25 26 def exact_module_a(filename, modname, funcname): 27 if modname is None: 28 return None 29 return modname == 'some.module' 30 31 def exact_module_b(filename, modname, funcname): 32 if modname is None: 33 return None 34 return modname == 'some.other.module' 35 36 c = Config() 37 s = Selector(c) 38 s.tests = [ '/a/file.py', 'some.module' ] 39 40 # in these cases, there is a test that doesn't care 41 # so they all pass 42 assert s.anytest(exact_file_a) 43 assert s.anytest(exact_file_b) 44 assert s.anytest(exact_module_a) 45 assert s.anytest(exact_module_b) 46 47 # no test matches file b 48 s.tests = [ '/a/file.py' ] 49 assert s.anytest(exact_file_a) 50 assert not s.anytest(exact_file_b) 51 assert s.anytest(exact_module_a) 52 assert s.anytest(exact_module_b) 53 54 s.tests = [ '/a/file.py', '/that/file.py' ] 55 assert s.anytest(exact_file_a) 56 assert not s.anytest(exact_file_b) 57 assert s.anytest(exact_module_a) 58 assert s.anytest(exact_module_b) 59 60 # no test matches module b 61 s.tests = [ 'some.module' ] 62 assert s.anytest(exact_file_a) 63 assert s.anytest(exact_file_b) 64 assert s.anytest(exact_module_a) 65 assert not s.anytest(exact_module_b) 66 67 # no test matches module b 68 s.tests = [ 'some.module', 'blah.blah' ] 69 assert s.anytest(exact_file_a) 70 assert s.anytest(exact_file_b) 71 assert s.anytest(exact_module_a) 72 assert not s.anytest(exact_module_b) 73 14 74 def test_exclude(self): 15 75 s = Selector(Config()) … … 22 82 assert s.matches('test_me') 23 83 assert not s2.matches('test_me') 24 25 84 26 85 def test_include(self): … … 34 93 assert not s.matches('meatball') 35 94 assert s2.matches('meatball') 36 37 95 38 96 def test_want_class(self): … … 218 276 219 277 if __name__ == '__main__': 278 # import logging 279 # logging.basicConfig() 280 # log.setLevel(logging.DEBUG) 220 281 unittest.main() -
trunk/st/unit_tests/test_utils.py
r14 r18 1 1 import unittest 2 2 import nose 3 import nose.case 3 4 4 5 class TestUtils(unittest.TestCase): … … 36 37 37 38 f = Foo() 39 40 class FooTC(unittest.TestCase): 41 def test_one(self): 42 pass
