LoginSignup
2
2

More than 5 years have passed since last update.

メソッドとかの呼び出し回数をカウント/検証する.

Last updated at Posted at 2012-01-31

前にうpしたスニペット( http://qiita.com/items/1321 )に依存しています. テストとかでメソッドの呼び出しをカウント/検証します.

from unittest import TestCase


class CallCounter(object):
    """Check a numbe of time a callable is called."""

    def __new__(cls, *args, **kargs):
        inst = super(CallCounter, cls).__new__(cls, *args, **kargs)
        inst._patch_mgr = PatchManager()
        inst._targets = {}
        return inst

    class FailedVerification(Exception):
        pass

    class CallCountManager(object):
        def __init__ (self, target, name, expected):
            self.__target = target
            self.__name = name
            self.__original = getattr(target, name)
            self.__count = 0
            self.__expected = expected

        def __call__(self, *args, **kargs):
            self.__count += 1
            return self.__original(*args, **kargs)

        def __verify(self):
            if self.__count == self.__expected:
                return

            msg = '%s.%s should be called %d times but %d' % \
                  (self.__target.__name__, self.__name, self.__expected,
                   self.__count,)
            raise CallCounter.FailedVerification(msg)

    def ensure(self, target, name, count):
        counter = self.CallCountManager(target, name, count)
        key = '%s.%s'%(target.__name__, name)
        self._targets[key] = counter
        self._patch_mgr.attach(target, name, counter)
        return

    def verify(self):
        for key, counter in self._targets.iteritems():
            counter._CallCountManager__verify()
        return

    def end(self):
        self._patch_mgr.detach_all()
        return

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.end()
        if exc_type:
            return False
        return True


class TestCallCounter(TestCase):
    """Test for test.CallCounter."""

    def test_1(self):
        """Call it simply."""

        c = CallCounter()

        import datetime
        original = datetime.datetime
        c.ensure(datetime, 'datetime', 1)
        self.assert_(isinstance(datetime.datetime,
                                CallCounter.CallCountManager))
        self.assertNotEqual(datetime.datetime, original)

        # Call it first.
        datetime.datetime(year=2011, month=3, day=4)
        c.verify()

        # Call it second.
        datetime.datetime(year=2011, month=3, day=4)
        with self.assertRaises(CallCounter.FailedVerification):
            c.verify()

        # Verify a clearance.
        c.end()
        self.assertEqual(datetime.datetime, original)

        return

    def test_2(self):
        """Call it simply."""

        c = CallCounter()

        import datetime
        original = datetime.datetime
        c.ensure(datetime, 'datetime', 0)
        self.assertNotEqual(datetime.datetime, original)

        # Call it and verify.
        datetime.datetime(year=2011, month=3, day=4)
        with self.assertRaises(CallCounter.FailedVerification):
            c.verify()

        c.end()
        self.assertEqual(datetime.datetime, original)

        return

    def test_3(self):
        """Use it with `with statement`."""

        import datetime
        original = datetime.datetime
        with self.assertRaises(CallCounter.FailedVerification):
            with CallCounter() as c:
                c.ensure(datetime, 'datetime', 0)
                self.assertNotEqual(datetime.datetime, original)

                # Call it and verify.
                datetime.datetime(year=2011, month=3, day=4)
                c.verify()

        self.assertEqual(datetime.datetime, original)

        return

    def test_4(self):
        """Exception is happend in with statement."""

        import datetime
        original = datetime.datetime
        with self.assertRaises(AssertionError):
            with CallCounter() as c:
                c.ensure(datetime, 'datetime', 0)
                self.assertNotEqual(datetime.datetime, original)

                # Call it and verify.
                datetime.datetime(year=2011, month=3, day=4)
                raise AssertionError()

        self.assertEqual(datetime.datetime, original)

        return
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2