def run_features(self, *features, **kwargs): """ Run the specified features. """ # named keyword args and variable positional args aren't supported on # Python 2 verbosity = kwargs.get('verbosity') stream = kwargs.get('stream') force_color = kwargs.get('force_color', False) if stream is None and isinstance(sys.stdout, CAPTURED_OUTPUTS): # Don't show results of running the inner tests if the outer Nose # redirects output stream = str_io() CALLBACK_REGISTRY.clear(priority_class=PriorityClass.USER) STEP_REGISTRY.clear() world.__dict__.clear() argv = ['aloe'] if verbosity: argv += ['--verbosity', str(verbosity)] if force_color: argv += ['--color'] argv += list(features) return TestRunner(exit=False, argv=argv, stream=stream)
def from_file(cls, file_): """ Construct a test class from a feature file. """ feature = TestFeature.from_file(file_) background = cls.make_background(feature.background) scenarios = [ cls.make_scenario(scenario, i + 1) for i, scenario in enumerate(feature.scenarios) ] before_feature, after_feature = \ CALLBACK_REGISTRY.before_after('feature') members = { 'feature': feature, 'background': background, 'before_feature': staticmethod(before_feature), 'after_feature': staticmethod(after_feature), } members.update({ scenario.__name__: scenario for scenario in scenarios }) class_name = identifier(feature.name) testclass = type(class_name, (cls,), members) testclass.feature.testclass = testclass return testclass
def run_features(self, *features, **kwargs): """ Run the specified features. """ # named keyword args and variable positional args aren't supported on # Python 2 verbosity = kwargs.get('verbosity') stream = kwargs.get('stream') force_color = kwargs.get('force_color', False) if stream is None and isinstance(sys.stdout, CAPTURED_OUTPUTS): # Don't show results of running the inner tests if the outer Nose # redirects output stream = TestWrapperIO() # Reset the state of callbacks and steps so that individual tests don't # affect each other CALLBACK_REGISTRY.clear(priority_class=PriorityClass.USER) STEP_REGISTRY.clear() world.__dict__.clear() argv = ['aloe'] if verbosity: argv += ['--verbosity', str(verbosity)] if force_color: argv += ['--color'] argv += list(features) # Save the loaded module list to restore later old_modules = set(sys.modules.keys()) result = TestRunner(exit=False, argv=argv, stream=stream) result.captured_stream = stream # To avoid affecting the (outer) testsuite and its subsequent tests, # unload all modules that were newly loaded. This also ensures that they # are loaded again for the next tests, registering relevant steps and # hooks. new_modules = set(sys.modules.keys()) for module_name in new_modules - old_modules: del sys.modules[module_name] return result
def make_steps(cls, step_container, steps, is_background, outline=None): """ Construct either a scenario or a background calling the specified steps. The method will have debugging information corresponding to the lines in the feature file. """ assert len(steps) > 0 step_definitions = [cls.prepare_step(step) for step in steps] source = 'def run_steps(self):\n' if not is_background: source += ' self.background()\n' source += '\n'.join( ' func{i}(step{i}, *args{i}, **kwargs{i})'.format(i=i) for i in range(len(step_definitions))) source = ast.parse(source) # Set locations of the steps for step, step_call in zip(steps, source.body[0].body[1:]): for node in ast.walk(step_call): node.lineno = step.described_at.line # Supply all the step functions and arguments context = { k + str(i): v for i, definition in enumerate(step_definitions) for k, v in definition.items() } if is_background: func_name = 'background' else: func_name = step_container.name run_steps = make_function( source=source, context=context, source_file=step_container.described_at.file, name=func_name, ) try: tags = step_container.tags except AttributeError: tags = () for tag in tags: run_steps = attr(tag)(run_steps) if not is_background: run_steps = CALLBACK_REGISTRY.wrap('example', run_steps, step_container, outline, steps) return run_steps
def ensure_before_callbacks(self): """ Before the first test, run the "before all" callbacks. """ if not hasattr(self, 'after_hook'): before_all, after_all = CALLBACK_REGISTRY.before_after('all') before_all() self.after_hook = after_all
def make_steps(cls, step_container, steps, is_background, outline=None): """ Construct either a scenario or a background calling the specified steps. The method will have debugging information corresponding to the lines in the feature file. """ assert len(steps) > 0 step_definitions = [ cls.prepare_step(step) for step in steps ] source = 'def run_steps(self):\n' if not is_background: source += ' self.background()\n' source += '\n'.join( ' func{i}(step{i}, *args{i}, **kwargs{i})'.format(i=i) for i in range(len(step_definitions)) ) source = ast.parse(source) # Set locations of the steps for step, step_call in zip(steps, source.body[0].body[1:]): for node in ast.walk(step_call): node.lineno = step.line # Supply all the step functions and arguments context = { k + str(i): v for i, definition in enumerate(step_definitions) for k, v in definition.items() } if is_background: func_name = 'background' else: func_name = step_container.name run_steps = make_function( source=source, context=context, source_file=step_container.filename, name=func_name, ) if not is_background: run_steps = CALLBACK_REGISTRY.wrap('example', run_steps, step_container, outline, steps) return run_steps
def prepare_step(cls, step): """ Find a definition for the step. Returns a dictionary of: step, func, args, kwargs, where: - step is the original step - func is the function to run (wrapped in callbacks) - args and kwargs are the arguments to pass to the function """ func, args, kwargs = STEP_REGISTRY.match_step(step) func = CALLBACK_REGISTRY.wrap('step', func, step) return { 'step': step, 'func': func, 'args': args, 'kwargs': kwargs, }
def make_steps(cls, step_container, steps, is_background, outline=None): """ Construct either a scenario or a background calling the specified steps. The method will have debugging information corresponding to the lines in the feature file. """ assert steps step_definitions = [cls.prepare_step(step) for step in steps] source = 'def run_steps(self):\n' if not is_background: source += ' self.background()\n' source += '\n'.join( # This has to be a single statement, in order to set its source # location as a whole below """ try: step{i}.test = self func{i}(step{i}, *args{i}, **kwargs{i}) finally: step{i}.test = None """.format(i=i) for i in range(len(step_definitions))) source = ast.parse(source) # Set locations of the steps step_source = source.body[0].body if not is_background: # There is no source for the background() call step_source = step_source[1:] for step, step_call in zip(steps, step_source): for node in ast.walk(step_call): node.lineno = step.line # Supply all the step functions and arguments context = { k + str(i): v for i, definition in enumerate(step_definitions) for k, v in definition.items() } if is_background: func_name = 'background' else: func_name = step_container.name run_steps = make_function( source=source, context=context, source_file=step_container.filename, name=func_name, ) if not is_background: run_steps = CALLBACK_REGISTRY.wrap('example', run_steps, step_container, outline, steps) return run_steps
def make_examples(cls, scenario, index): """ Construct methods for running all the examples of a scenario. index is the 1-based number of the scenario in the feature. """ if scenario.outlines: outline_example = [] for i, (outline, steps) in enumerate(scenario.evaluated, 1): # Create a function calling the real scenario example to show # the right location in the outline source = """ def run_example(self): outline(self) """ source = ast.parse(source) # Set location of the call for node in ast.walk(source.body[0].body[0]): node.lineno = outline.line context = { 'outline': cls.make_steps(scenario, steps, is_background=False, is_outline=True, outline=outline) } outline_example.append( cls.make_example( make_function( source=source, context=context, source_file=scenario.feature.filename, name='{}: Example {}'.format(scenario.name, i), ), scenario, index, )) source = """ def run_example(self): for outline in outlines: outline(self) """ context = {'outlines': outline_example} yield (cls.make_example( CALLBACK_REGISTRY.wrap( 'example', make_function( source=source, context=context, source_file=scenario.feature.filename, name='{}: Example {}'.format(scenario.name, index), ), scenario, None, scenario.steps), scenario, index, )) if scenario.keyword == 'Scenario Outline': pass elif scenario.outline_header is None: yield cls.make_example( cls.make_steps( scenario, scenario.steps, is_background=False, ), scenario, index, )