def test_import_relative(self): """Tests if relative imports are tracked on the module object.""" path = os.path.join(BASEDIR, 'selftests', 'functional', 'test_basic.py') module = PythonModule(path) for _ in module.iter_classes(): pass self.assertIn('TestCaseTmpDir', module.imported_symbols)
def test_is_avocado_test(self): passtest_path = os.path.join(BASEDIR, 'examples', 'tests', 'passtest.py') passtest_module = PythonModule(passtest_path) classes = [klass for klass in passtest_module.iter_classes()] # there's only one class and one *worthy* Test import in passtest.py self.assertEqual(len(classes), 1) self.assertEqual(len(passtest_module.klass_imports), 1) self.assertEqual(len(passtest_module.mod_imports), 0) self.assertTrue(passtest_module.is_matching_klass(classes[0]))
def test_import_of_all_module_level(self): """ Checks if all levels of a module import are taken into account This specific source file imports unittest.mock, and we want to make sure that unittest is accounted for. """ path = os.path.join(BASEDIR, 'selftests', 'unit', 'test_loader.py') module = PythonModule(path, 'unittest', 'TestCase') for _ in module.iter_classes(): pass self.assertIn('unittest', module.mod_imports)
class PythonModuleSelf(unittest.TestCase): """ Has tests based on this source code file """ def setUp(self): self.path = os.path.abspath(os.path.dirname(get_this_file())) self.module = PythonModule(self.path) def test_add_imported_empty(self): self.assertEqual(self.module.imported_symbols, {}) def test_add_imported_symbols_from_module(self): import_stm = ast.ImportFrom(module='foo', names=[ast.Name(name='bar', asname=None)]) self.module.add_imported_symbol(import_stm) self.assertEqual(self.module.imported_symbols['bar'].module_path, 'foo') self.assertEqual(self.module.imported_symbols['bar'].symbol, 'bar') def test_add_imported_object_from_module_asname(self): import_stm = ast.ImportFrom(module='foo', names=[ast.Name(name='bar', asname='baz')]) self.module.add_imported_symbol(import_stm) self.assertEqual(self.module.imported_symbols['baz'].module_path, 'foo') self.assertEqual(self.module.imported_symbols['baz'].symbol, 'bar') def test_is_not_avocado_test(self): self.assertFalse(self.module.is_matching_klass(ast.ClassDef())) def test_is_not_avocado_tests(self): for klass in self.module.iter_classes(): self.assertFalse(self.module.is_matching_klass(klass))
def setUp(self): self.path = os.path.abspath(os.path.dirname(get_this_file())) self.module = PythonModule(self.path)
def find_python_tests(target_module, target_class, determine_match, path): """ Attempts to find Python tests from source files A Python test in this context is a method within a specific type of class (or that inherits from a specific class). :param target_module: the name of the module from which a class should have come from. When attempting to find a Python unittest, the target_module will most probably be "unittest", as per the standard library module name. When attempting to find Avocado tests, the target_module will most probably be "avocado". :type target_module: str :param target_class: the name of the class that is considered to contain test methods. When attempting to find Python unittests, the target_class will most probably be "TestCase". When attempting to find Avocado tests, the target_class will most probably be "Test". :type target_class: str :type determine_match: a callable that will determine if a given module and class is contains valid Python tests :type determine_match: function :param path: path to a Python source code file :type path: str :returns: tuple where first item is dict with class name and additional info such as method names and tags; the second item is set of class names which look like Python tests but have been forcefully disabled. :rtype: tuple """ module = PythonModule(path, target_module, target_class) # The resulting test classes result = collections.OrderedDict() disabled = set() for klass in module.iter_classes(): docstring = ast.get_docstring(klass) # Looking for a class that has in the docstring either # ":avocado: enable" or ":avocado: disable if check_docstring_directive(docstring, 'disable'): disabled.add(klass.name) continue if check_docstring_directive(docstring, 'enable'): info = get_methods_info(klass.body, get_docstring_directives_tags(docstring), get_docstring_directives_requirements( docstring)) result[klass.name] = info continue # From this point onwards we want to do recursive discovery, but # for now we don't know whether it is avocado.Test inherited # (Ifs are optimized for readability, not speed) # If "recursive" tag is specified, it is forced as test if check_docstring_directive(docstring, 'recursive'): match = True else: match = module.is_matching_klass(klass) info = get_methods_info(klass.body, get_docstring_directives_tags(docstring), get_docstring_directives_requirements( docstring)) # Getting the list of parents of the current class parents = klass.bases match = _examine_same_module(parents, info, disabled, match, module, target_module, target_class, determine_match) # If there are parents left to be discovered, they # might be in a different module. for parent in parents: try: (parent_class, imported_symbol, symbol_is_module) = _get_attributes_for_further_examination(parent, module) found_spec = imported_symbol.get_importable_spec(symbol_is_module) if found_spec is None: continue except ClassNotSuitable: continue _info, _dis, _match = _examine_class(target_module, target_class, determine_match, found_spec.origin, parent_class, match) if _info: info.extend(_info) disabled.update(_dis) if _match is not match: match = _match # Only update the results if this was detected as 'avocado.Test' if match: result[klass.name] = info return result, disabled
def _examine_class(target_module, target_class, determine_match, path, class_name, match): """ Examine a class from a given path :param target_module: the name of the module from which a class should have come from. When attempting to find a Python unittest, the target_module will most probably be "unittest", as per the standard library module name. When attempting to find Avocado tests, the target_module will most probably be "avocado". :type target_module: str :param target_class: the name of the class that is considered to contain test methods. When attempting to find Python unittests, the target_class will most probably be "TestCase". When attempting to find Avocado tests, the target_class will most probably be "Test". :type target_class: str :param determine_match: a callable that will determine if a match has occurred or not :type determine_match: function :param path: path to a Python source code file :type path: str :param class_name: the specific class to be found :type path: str :param match: whether the inheritance from <target_module.target_class> has been determined or not :type match: bool :returns: tuple where first item is a list of test methods detected for given class; second item is set of class names which look like avocado tests but are force-disabled. :rtype: tuple """ module = PythonModule(path, target_module, target_class) info = [] disabled = set() for klass in module.iter_classes(class_name): if class_name != klass.name: continue docstring = ast.get_docstring(klass) if match is False: match = module.is_matching_klass(klass) info = get_methods_info(klass.body, get_docstring_directives_tags(docstring), get_docstring_directives_requirements( docstring)) # Getting the list of parents of the current class parents = klass.bases match = _examine_same_module(parents, info, disabled, match, module, target_module, target_class, determine_match) # If there are parents left to be discovered, they # might be in a different module. for parent in parents: try: (parent_class, imported_symbol, symbol_is_module) = _get_attributes_for_further_examination(parent, module) found_spec = imported_symbol.get_importable_spec(symbol_is_module) if found_spec is None: continue except ClassNotSuitable: continue _info, _disabled, _match = _examine_class(target_module, target_class, determine_match, found_spec.origin, parent_class, match) if _info: _extend_test_list(info, _info) disabled.update(_disabled) if _match is not match: match = _match if not match and module.interesting_klass_found: imported_symbol = module.imported_symbols[class_name] if imported_symbol: found_spec = imported_symbol.get_importable_spec() if found_spec: _info, _disabled, _match = _examine_class(target_module, target_class, determine_match, found_spec.origin, class_name, match) if _info: _extend_test_list(info, _info) disabled.update(_disabled) if _match is not match: match = _match return info, disabled, match