Source code for traits.testing.unittest_tools

#------------------------------------------------------------------------------
# Copyright (c) 2005, Enthought, Inc.
# All rights reserved.
#
# This software is provided without warranty under the terms of the BSD
# license included in /LICENSE.txt and may be redistributed only
# under the conditions described in the aforementioned license.  The license
# is also available online at http://www.enthought.com/licenses/BSD.txt
# Thanks for using Enthought open source!
#------------------------------------------------------------------------------
""" Trait assert mixin class to simplify test implementation for Trait
Classes.

"""


class _AssertTraitChangesContext(object):
    """ A context manager used to implement the trait change assert methods.

    Attributes
    ----------
    obj : HasTraits
        The HasTraits class instance who's class trait will change.

    xname : str
        The extended trait name of trait changes to listen too.

    count : int, optional
        The expected number of times the event should be fired. When None
        (default value) there is no check for the number of times the
        change event was fired.

    events : list of tuples
        A list with tuple elements containing the arguments of an
        `on_trait_change` event signature (<object>, <name>, <old>, <new>).

    Raises
    ------
    AssertionError :
          When the desired number of trait changed did not take place or when
          `count = None` and no trait change took place.

    """

    def __init__(self, obj, xname, count, test_case):
        """ Initialize the trait change assertion context manager.

        Parameters
        ----------
        obj : HasTraits
            The HasTraits class instance who's class trait will change.

        xname : str
            The extended trait name of trait changes to listen too.

        count : int, optional
            The expected number of times the event should be fired. When None
            (default value) there is no check for the number of times the
            change event was fired.

        test_case : TestCase
            A unittest TestCase where to raise the failureException if
            necessary.

        Notes
        -----
        - Checking if the provided xname corresponds to valid traits in
          the class is not implemented yet.

        """
        self.obj = obj
        self.xname = xname
        self.count = count
        self.events = []
        self.failureException = test_case.failureException

    def _listener(self, obj, name, old, new):
        """ Dummy trait listener
        """
        self.events.append((obj, name, old, new))

    def __enter__(self):
        """ Bind the trait listener
        """
        self.obj.on_trait_change(self._listener, self.xname)
        return self

    def __exit__(self, exc_type, exc_value, tb):
        """ Remove the trait listener

        """
        if exc_type is not None:
            return

        self.obj.on_trait_change(self._listener, self.xname, remove=True)
        if self.count is not None and len(self.events) != self.count:
            msg = 'Change event for {0} was fired {1} times instead of {2}'
            items = self.xname, len(self.events), self.count
            raise self.failureException(msg.format(*items))
        elif self.count is None and not self.events:
            msg = 'A change event was not fired for: {0}'.format(self.xname)
            raise self.failureException(msg)

[docs]class UnittestTools(object): """ Mixin class to augment the unittest.TestCase class with useful trait related assert methods. """
[docs] def assertTraitChanges(self, obj, trait, count=None): """ Assert that the class trait changes exactly n times. Used in a with statement to assert that a class trait has changed during the execution of the code inside the with context block (similar to the assertRaises method). Please note that the context manager returns itself and the user can introspect the information of the fired events by accessing the ``events`` attribute of the context object. The attribute is a list with tuple elements containing the arguments of an `on_trait_change` event signature (<object>, <name>, <old>, <new>). **Example**:: class MyClass(HasTraits): number = Float(2.0) my_class = MyClass() with self.assertTraitChanges(my_class, 'number') as ctx: my_class.number = 3.0 self.assert(ctx.events, [(my_class, 'number', 2.0, 3.0)] Parameters ---------- obj : HasTraits The HasTraits class instance who's class trait will change. xname : str The extended trait name of trait changes to listen too. count : int, optional The expected number of times the event should be fired. When None (default value) there is no check for the number of times the change event was fired. Notes ----- - Checking if the provided xname corresponds to valid traits in the class is not implemented yet. """ return _AssertTraitChangesContext(obj, trait, count, self)
[docs] def assertTraitDoesNotChange(self, obj, xname): """ Assert that no trait event is fired. Used in a with statement to assert that a class trait has not changed during the execution of the code inside the with statement block. **Example**:: class MyClass(HasTraits): number = Float(2.0) name = String my_class = MyClass() with self.assertTraitDoesNotChange(my_class, 'name'): my_class.number = 2.0 Parameters ---------- obj : HasTraits The HasTraits class instance who's class trait will change. xname : str The extended trait name of trait changes to listen too. Notes ----- - Checking if the provided xname corresponds to valid traits in the class is not implemented yet. """ return _AssertTraitChangesContext(obj, xname, 0, self)