1 import os 2 import re 3 import sys 4 5 import unittest 6 7 8 class TestDiscovery(unittest.TestCase): 9 10 # Heavily mocked tests so I can avoid hitting the filesystem 11 def test_get_name_from_path(self): 12 loader = unittest.TestLoader() 13 14 loader._top_level_dir = '/foo' 15 name = loader._get_name_from_path('/foo/bar/baz.py') 16 self.assertEqual(name, 'bar.baz') 17 18 if not __debug__: 19 # asserts are off 20 return 21 22 with self.assertRaises(AssertionError): 23 loader._get_name_from_path('/bar/baz.py') 24 25 def test_find_tests(self): 26 loader = unittest.TestLoader() 27 28 original_listdir = os.listdir 29 def restore_listdir(): 30 os.listdir = original_listdir 31 original_isfile = os.path.isfile 32 def restore_isfile(): 33 os.path.isfile = original_isfile 34 original_isdir = os.path.isdir 35 def restore_isdir(): 36 os.path.isdir = original_isdir 37 38 path_lists = [['test1.py', 'test2.py', 'not_a_test.py', 'test_dir', 39 'test.foo', 'test-not-a-module.py', 'another_dir'], 40 ['test3.py', 'test4.py', ]] 41 os.listdir = lambda path: path_lists.pop(0) 42 self.addCleanup(restore_listdir) 43 44 def isdir(path): 45 return path.endswith('dir') 46 os.path.isdir = isdir 47 self.addCleanup(restore_isdir) 48 49 def isfile(path): 50 # another_dir is not a package and so shouldn't be recursed into 51 return not path.endswith('dir') and not 'another_dir' in path 52 os.path.isfile = isfile 53 self.addCleanup(restore_isfile) 54 55 loader._get_module_from_name = lambda path: path + ' module' 56 loader.loadTestsFromModule = lambda module: module + ' tests' 57 58 top_level = os.path.abspath('/foo') 59 loader._top_level_dir = top_level 60 suite = list(loader._find_tests(top_level, 'test*.py')) 61 62 expected = [name + ' module tests' for name in 63 ('test1', 'test2')] 64 expected.extend([('test_dir.%s' % name) + ' module tests' for name in 65 ('test3', 'test4')]) 66 self.assertEqual(suite, expected) 67 68 def test_find_tests_with_package(self): 69 loader = unittest.TestLoader() 70 71 original_listdir = os.listdir 72 def restore_listdir(): 73 os.listdir = original_listdir 74 original_isfile = os.path.isfile 75 def restore_isfile(): 76 os.path.isfile = original_isfile 77 original_isdir = os.path.isdir 78 def restore_isdir(): 79 os.path.isdir = original_isdir 80 81 directories = ['a_directory', 'test_directory', 'test_directory2'] 82 path_lists = [directories, [], [], []] 83 os.listdir = lambda path: path_lists.pop(0) 84 self.addCleanup(restore_listdir) 85 86 os.path.isdir = lambda path: True 87 self.addCleanup(restore_isdir) 88 89 os.path.isfile = lambda path: os.path.basename(path) not in directories 90 self.addCleanup(restore_isfile) 91 92 class Module(object): 93 paths = [] 94 load_tests_args = [] 95 96 def __init__(self, path): 97 self.path = path 98 self.paths.append(path) 99 if os.path.basename(path) == 'test_directory': 100 def load_tests(loader, tests, pattern): 101 self.load_tests_args.append((loader, tests, pattern)) 102 return 'load_tests' 103 self.load_tests = load_tests 104 105 def __eq__(self, other): 106 return self.path == other.path 107 108 # Silence py3k warning 109 __hash__ = None 110 111 loader._get_module_from_name = lambda name: Module(name) 112 def loadTestsFromModule(module, use_load_tests): 113 if use_load_tests: 114 raise self.failureException('use_load_tests should be False for packages') 115 return module.path + ' module tests' 116 loader.loadTestsFromModule = loadTestsFromModule 117 118 loader._top_level_dir = '/foo' 119 # this time no '.py' on the pattern so that it can match 120 # a test package 121 suite = list(loader._find_tests('/foo', 'test*')) 122 123 # We should have loaded tests from the test_directory package by calling load_tests 124 # and directly from the test_directory2 package 125 self.assertEqual(suite, 126 ['load_tests', 'test_directory2' + ' module tests']) 127 self.assertEqual(Module.paths, ['test_directory', 'test_directory2']) 128 129 # load_tests should have been called once with loader, tests and pattern 130 self.assertEqual(Module.load_tests_args, 131 [(loader, 'test_directory' + ' module tests', 'test*')]) 132 133 def test_discover(self): 134 loader = unittest.TestLoader() 135 136 original_isfile = os.path.isfile 137 original_isdir = os.path.isdir 138 def restore_isfile(): 139 os.path.isfile = original_isfile 140 141 os.path.isfile = lambda path: False 142 self.addCleanup(restore_isfile) 143 144 orig_sys_path = sys.path[:] 145 def restore_path(): 146 sys.path[:] = orig_sys_path 147 self.addCleanup(restore_path) 148 149 full_path = os.path.abspath(os.path.normpath('/foo')) 150 with self.assertRaises(ImportError): 151 loader.discover('/foo/bar', top_level_dir='/foo') 152 153 self.assertEqual(loader._top_level_dir, full_path) 154 self.assertIn(full_path, sys.path) 155 156 os.path.isfile = lambda path: True 157 os.path.isdir = lambda path: True 158 159 def restore_isdir(): 160 os.path.isdir = original_isdir 161 self.addCleanup(restore_isdir) 162 163 _find_tests_args = [] 164 def _find_tests(start_dir, pattern): 165 _find_tests_args.append((start_dir, pattern)) 166 return ['tests'] 167 loader._find_tests = _find_tests 168 loader.suiteClass = str 169 170 suite = loader.discover('/foo/bar/baz', 'pattern', '/foo/bar') 171 172 top_level_dir = os.path.abspath('/foo/bar') 173 start_dir = os.path.abspath('/foo/bar/baz') 174 self.assertEqual(suite, "['tests']") 175 self.assertEqual(loader._top_level_dir, top_level_dir) 176 self.assertEqual(_find_tests_args, [(start_dir, 'pattern')]) 177 self.assertIn(top_level_dir, sys.path) 178 179 def test_discover_with_modules_that_fail_to_import(self): 180 loader = unittest.TestLoader() 181 182 listdir = os.listdir 183 os.listdir = lambda _: ['test_this_does_not_exist.py'] 184 isfile = os.path.isfile 185 os.path.isfile = lambda _: True 186 orig_sys_path = sys.path[:] 187 def restore(): 188 os.path.isfile = isfile 189 os.listdir = listdir 190 sys.path[:] = orig_sys_path 191 self.addCleanup(restore) 192 193 suite = loader.discover('.') 194 self.assertIn(os.getcwd(), sys.path) 195 self.assertEqual(suite.countTestCases(), 1) 196 test = list(list(suite)[0])[0] # extract test from suite 197 198 with self.assertRaises(ImportError): 199 test.test_this_does_not_exist() 200 201 def test_command_line_handling_parseArgs(self): 202 # Haha - take that uninstantiable class 203 program = object.__new__(unittest.TestProgram) 204 205 args = [] 206 def do_discovery(argv): 207 args.extend(argv) 208 program._do_discovery = do_discovery 209 program.parseArgs(['something', 'discover']) 210 self.assertEqual(args, []) 211 212 program.parseArgs(['something', 'discover', 'foo', 'bar']) 213 self.assertEqual(args, ['foo', 'bar']) 214 215 def test_command_line_handling_do_discovery_too_many_arguments(self): 216 class Stop(Exception): 217 pass 218 def usageExit(): 219 raise Stop 220 221 program = object.__new__(unittest.TestProgram) 222 program.usageExit = usageExit 223 program.testLoader = None 224 225 with self.assertRaises(Stop): 226 # too many args 227 program._do_discovery(['one', 'two', 'three', 'four']) 228 229 230 def test_command_line_handling_do_discovery_uses_default_loader(self): 231 program = object.__new__(unittest.TestProgram) 232 233 class Loader(object): 234 args = [] 235 def discover(self, start_dir, pattern, top_level_dir): 236 self.args.append((start_dir, pattern, top_level_dir)) 237 return 'tests' 238 239 program.testLoader = Loader() 240 program._do_discovery(['-v']) 241 self.assertEqual(Loader.args, [('.', 'test*.py', None)]) 242 243 def test_command_line_handling_do_discovery_calls_loader(self): 244 program = object.__new__(unittest.TestProgram) 245 246 class Loader(object): 247 args = [] 248 def discover(self, start_dir, pattern, top_level_dir): 249 self.args.append((start_dir, pattern, top_level_dir)) 250 return 'tests' 251 252 program._do_discovery(['-v'], Loader=Loader) 253 self.assertEqual(program.verbosity, 2) 254 self.assertEqual(program.test, 'tests') 255 self.assertEqual(Loader.args, [('.', 'test*.py', None)]) 256 257 Loader.args = [] 258 program = object.__new__(unittest.TestProgram) 259 program._do_discovery(['--verbose'], Loader=Loader) 260 self.assertEqual(program.test, 'tests') 261 self.assertEqual(Loader.args, [('.', 'test*.py', None)]) 262 263 Loader.args = [] 264 program = object.__new__(unittest.TestProgram) 265 program._do_discovery([], Loader=Loader) 266 self.assertEqual(program.test, 'tests') 267 self.assertEqual(Loader.args, [('.', 'test*.py', None)]) 268 269 Loader.args = [] 270 program = object.__new__(unittest.TestProgram) 271 program._do_discovery(['fish'], Loader=Loader) 272 self.assertEqual(program.test, 'tests') 273 self.assertEqual(Loader.args, [('fish', 'test*.py', None)]) 274 275 Loader.args = [] 276 program = object.__new__(unittest.TestProgram) 277 program._do_discovery(['fish', 'eggs'], Loader=Loader) 278 self.assertEqual(program.test, 'tests') 279 self.assertEqual(Loader.args, [('fish', 'eggs', None)]) 280 281 Loader.args = [] 282 program = object.__new__(unittest.TestProgram) 283 program._do_discovery(['fish', 'eggs', 'ham'], Loader=Loader) 284 self.assertEqual(program.test, 'tests') 285 self.assertEqual(Loader.args, [('fish', 'eggs', 'ham')]) 286 287 Loader.args = [] 288 program = object.__new__(unittest.TestProgram) 289 program._do_discovery(['-s', 'fish'], Loader=Loader) 290 self.assertEqual(program.test, 'tests') 291 self.assertEqual(Loader.args, [('fish', 'test*.py', None)]) 292 293 Loader.args = [] 294 program = object.__new__(unittest.TestProgram) 295 program._do_discovery(['-t', 'fish'], Loader=Loader) 296 self.assertEqual(program.test, 'tests') 297 self.assertEqual(Loader.args, [('.', 'test*.py', 'fish')]) 298 299 Loader.args = [] 300 program = object.__new__(unittest.TestProgram) 301 program._do_discovery(['-p', 'fish'], Loader=Loader) 302 self.assertEqual(program.test, 'tests') 303 self.assertEqual(Loader.args, [('.', 'fish', None)]) 304 self.assertFalse(program.failfast) 305 self.assertFalse(program.catchbreak) 306 307 Loader.args = [] 308 program = object.__new__(unittest.TestProgram) 309 program._do_discovery(['-p', 'eggs', '-s', 'fish', '-v', '-f', '-c'], 310 Loader=Loader) 311 self.assertEqual(program.test, 'tests') 312 self.assertEqual(Loader.args, [('fish', 'eggs', None)]) 313 self.assertEqual(program.verbosity, 2) 314 self.assertTrue(program.failfast) 315 self.assertTrue(program.catchbreak) 316 317 def test_detect_module_clash(self): 318 class Module(object): 319 __file__ = 'bar/foo.py' 320 sys.modules['foo'] = Module 321 full_path = os.path.abspath('foo') 322 original_listdir = os.listdir 323 original_isfile = os.path.isfile 324 original_isdir = os.path.isdir 325 326 def cleanup(): 327 os.listdir = original_listdir 328 os.path.isfile = original_isfile 329 os.path.isdir = original_isdir 330 del sys.modules['foo'] 331 if full_path in sys.path: 332 sys.path.remove(full_path) 333 self.addCleanup(cleanup) 334 335 def listdir(_): 336 return ['foo.py'] 337 def isfile(_): 338 return True 339 def isdir(_): 340 return True 341 os.listdir = listdir 342 os.path.isfile = isfile 343 os.path.isdir = isdir 344 345 loader = unittest.TestLoader() 346 347 mod_dir = os.path.abspath('bar') 348 expected_dir = os.path.abspath('foo') 349 msg = re.escape(r"'foo' module incorrectly imported from %r. Expected %r. " 350 "Is this module globally installed?" % (mod_dir, expected_dir)) 351 self.assertRaisesRegexp( 352 ImportError, '^%s$' % msg, loader.discover, 353 start_dir='foo', pattern='foo.py' 354 ) 355 self.assertEqual(sys.path[0], full_path) 356 357 358 def test_discovery_from_dotted_path(self): 359 loader = unittest.TestLoader() 360 361 tests = [self] 362 expectedPath = os.path.abspath(os.path.dirname(unittest.test.__file__)) 363 364 self.wasRun = False 365 def _find_tests(start_dir, pattern): 366 self.wasRun = True 367 self.assertEqual(start_dir, expectedPath) 368 return tests 369 loader._find_tests = _find_tests 370 suite = loader.discover('unittest.test') 371 self.assertTrue(self.wasRun) 372 self.assertEqual(suite._tests, tests) 373 374 375 if __name__ == '__main__': 376 unittest.main() 377