Source code for fluenttest.test_case

"""Expose a TestCase class.

- TestCase: a basic Arrange, Act, Assert test case implementation

"""
import mock


[docs]class TestCase(object): """Arrange, Act, Assert test case. Sub-classes implement test cases by *arranging* the environment in the :meth:`.arrange` class method, perform the *action* in the :meth:`.act` class method, and implement *assertions* as test methods. The individual assertion methods have to be written in such a way that the test runner in use finds them. .. py:attribute:: allowed_exceptions The exception or list of exceptions that the test case is interested in capturing. An exception raised from :meth:`.act` will be stored in :attr:`exception`. .. py:attribute:: exception The exception that was thrown during the action or ``None``. """ allowed_exceptions = () """Catch this set of exception classes.""" @classmethod
[docs] def setUpClass(cls): """Arrange the environment and perform the action. This method ensures that :meth:`.arrange` and :meth:`.act` are invoked exactly once before the assertions are fired. If you do find the need to extend this method, you should call this implementation as the last statement in your extension method as it will perform the action under test when it is called. """ cls.exception = None cls._patches = [] cls.arrange() try: cls.act() except cls.allowed_exceptions as exc: cls.exception = exc finally: cls.destroy()
@classmethod
[docs] def tearDownClass(cls): """Stop any patches that have been created.""" for patcher in cls._patches: patcher.stop()
@classmethod
[docs] def arrange(cls): """Arrange the testing environment. Concrete test classes will probably override this method and should invoke this implementation via ``super()``. """ pass
@classmethod
[docs] def destroy(cls): """Perform post-test cleanup. Concrete tests classes may override this method if there are actions that need to be performed after :meth:`.act` is called. Subclasses should invoke this implementation via ``super()``. This method is guaranteed to be called *after* the action under test is invoked and before :meth:`.teardown_class`. It will be called after any captured exception has been caught. """ pass
@classmethod
[docs] def patch(cls, target, **kwargs): r"""Patch a named class or method. :param str target: the dotted-name to patch :returns: the result of starting the patch. This method calls :func:`mock.patch` with *target* and *\*\*kwargs*, saves the result, and returns the running patch. """ patcher = mock.patch(target, **kwargs) patched = patcher.start() cls._patches.append(patcher) return patched
@classmethod
[docs] def patch_instance(cls, target, **kwargs): r"""Patch a named class and return the created instance. :param str target: the dotted-name of the class to patch :returns: tuple of (patched class, patched instance) This method calls :meth:`.patch` with *\*\*kwargs* to patch *target* and returns a tuple containing the patched class as well as the ``return_value`` attribute of the patched class. This is useful if you want to patch a class and manipulate the result of the code under test creating an instance of the class. """ patched_class = cls.patch(target, **kwargs) return patched_class, patched_class.return_value
@classmethod
[docs] def act(cls): """The action to test. **Subclasses are required to replace this method.** """ raise NotImplementedError