summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mocker.py167
-rwxr-xr-xtest.py370
2 files changed, 484 insertions, 53 deletions
diff --git a/mocker.py b/mocker.py
index b8582ec..8523b21 100644
--- a/mocker.py
+++ b/mocker.py
@@ -1,4 +1,5 @@
import __builtin__
+import unittest
import inspect
import types
import sys
@@ -6,7 +7,7 @@ import os
import gc
-__all__ = ["Mocker", "expect", "SAME", "CONTAINS", "ANY", "VARIOUS"]
+__all__ = ["Mocker", "expect", "IS", "CONTAINS", "IN", "ANY", "ARGS", "KWARGS"]
ERROR_PREFIX = "[Mocker] "
@@ -51,6 +52,98 @@ class expect(object):
# --------------------------------------------------------------------
+# Extensions to Python's unittest.
+
+class MockerTestCase(unittest.TestCase):
+ """unittest.TestCase subclass with Mocker support.
+
+ @ivar mocker: The mocker instance.
+
+ This is a convenience only. Mocker may easily be used with the
+ standard C{unittest.TestCase} class if wanted.
+
+ Test methods have a Mocker instance available on C{self.mocker}.
+ At the end of each test method, expectations of the mocker will
+ be verified, and any requested changes made to the environment
+ will be restored.
+
+ In addition to the integration with Mocker, this class provides
+ a few additional helper methods.
+ """
+
+ expect = expect
+
+ def __init__(self, methodName="runTest"):
+ # So here is the trick: we take the real test method, wrap it on
+ # a function that do the job we have to do, and insert it in the
+ # *instance* dictionary, so that getattr() will return our
+ # replacement rather than the class method.
+ test_method = getattr(self, methodName, None)
+ if test_method is not None:
+ def test_method_wrapper():
+ try:
+ test_method()
+ except:
+ self.mocker.restore()
+ raise
+ else:
+ self.mocker.restore()
+ self.mocker.verify()
+ test_method_wrapper.__doc__ = test_method.__doc__
+ setattr(self, methodName, test_method_wrapper)
+
+ self.mocker = Mocker()
+
+ super(MockerTestCase, self).__init__(methodName)
+
+ def failUnlessIs(self, first, second, msg=None):
+ """Assert that C{first} is the same object as C{second}."""
+ if first is not second:
+ raise self.failureException(msg or "%r is not %r" % (first, second))
+
+ def failIfIs(self, first, second, msg=None):
+ """Assert that C{first} is not the same object as C{second}."""
+ if first is second:
+ raise self.failureException(msg or "%r is %r" % (first, second))
+
+ def failUnlessIn(self, first, second, msg=None):
+ """Assert that C{first} is contained in C{second}."""
+ if first not in second:
+ raise self.failureException(msg or "%r not in %r" % (first, second))
+
+ def failIfIn(self, first, second, msg=None):
+ """Assert that C{first} is not contained in C{second}."""
+ if first in second:
+ raise self.failureException(msg or "%r in %r" % (first, second))
+
+ def failUnlessApproximates(self, first, second, tolerance, msg=None):
+ """Assert that C{first} is near C{second} by at most C{tolerance}."""
+ if abs(first - second) > tolerance:
+ raise self.failureException(msg or "abs(%r - %r) > %r" %
+ (first, second, tolerance))
+
+ def failIfApproximates(self, first, second, tolerance, msg=None):
+ """Assert that C{first} is far from C{second} by at least C{tolerance}.
+ """
+ if abs(first - second) <= tolerance:
+ raise self.failureException(msg or "abs(%r - %r) <= %r" %
+ (first, second, tolerance))
+
+ assertIs = failUnlessIs
+ assertIsNot = failIfIs
+ assertIn = failUnlessIn
+ assertNotIn = failIfIn
+ assertApproximates = failUnlessApproximates
+ assertNotApproximates = failIfApproximates
+
+ # The following is provided for compatibility with Twisted's trial.
+ assertIdentical = assertIs
+ assertNotIdentical = assertIsNot
+ failUnlessIdentical = failUnlessIs
+ failIfIdentical = failIfIs
+
+
+# --------------------------------------------------------------------
# Mocker.
class classinstancemethod(object):
@@ -94,9 +187,9 @@ class MockerBase(object):
In this short excerpt a mock object is being created, then an
expectation of a call to the C{hello()} method was recorded, and
- when that happens the method should return the value C{10}. Then,
- the mocker is put in replay mode, and the expectation is satisfied
- by calling the C{hello()} method, which indeed returns 10. Finally,
+ when called the method should return the value C{10}. Then, the
+ mocker is put in replay mode, and the expectation is satisfied by
+ calling the C{hello()} method, which indeed returns 10. Finally,
a call to the L{restore()} method is performed to undo any needed
changes made in the environment, and the L{verify()} method is
called to ensure that all defined expectations were met.
@@ -346,7 +439,7 @@ class MockerBase(object):
object = getattr(object, attr)
break
mock = self.proxy(object, spec, type, name, passthrough)
- event = self.add_event(Event())
+ event = self._get_replay_restore_event()
event.add_task(ProxyReplacer(mock))
return mock
@@ -391,13 +484,21 @@ class MockerBase(object):
if spec is True:
spec = object
patcher = Patcher()
- event = self.add_event(Event())
+ event = self._get_replay_restore_event()
event.add_task(patcher)
mock = Mock(self, object=object, patcher=patcher,
passthrough=True, spec=spec)
object.__mocker_mock__ = mock
return mock
+ def on_restore(self, callback):
+ """Run C{callback()} when the environment state is restored.
+
+ @param callback: Any callable.
+ """
+ event = self._get_replay_restore_event()
+ event.add_task(OnRestoreCaller(callback))
+
def act(self, path):
"""This is called by mock objects whenever something happens to them.
@@ -676,6 +777,19 @@ class MockerBase(object):
self.verify()
return False
+ def _get_replay_restore_event(self):
+ """Return unique L{ReplayRestoreEvent}, creating if needed.
+
+ Some tasks only want to replay/restore. When that's the case,
+ they shouldn't act on other events during replay. Also, they
+ can all be put in a single event when that's the case. Thus,
+ we add a single L{ReplayRestoreEvent} as the first element of
+ the list.
+ """
+ if not self._events or type(self._events[0]) != ReplayRestoreEvent:
+ self._events.insert(0, ReplayRestoreEvent())
+ return self._events[0]
+
class OrderedContext(object):
@@ -1003,12 +1117,6 @@ class ANY(SpecialArgument):
ANY = ANY()
-class VARIOUS(SpecialArgument):
- """Matches zero or more arguments."""
-
-VARIOUS = VARIOUS()
-
-
class ARGS(SpecialArgument):
"""Matches zero or more positional arguments."""
@@ -1021,7 +1129,7 @@ class KWARGS(SpecialArgument):
KWARGS = KWARGS()
-class SAME(SpecialArgument):
+class IS(SpecialArgument):
def matches(self, other):
return self.object is other
@@ -1047,8 +1155,14 @@ class CONTAINS(SpecialArgument):
return self.object in other
+class IN(SpecialArgument):
+
+ def matches(self, other):
+ return other in self.object
+
+
def match_params(args1, kwargs1, args2, kwargs2):
- """Match the two sets of parameters, considering the special VARIOUS."""
+ """Match the two sets of parameters, considering special parameters."""
has_args = ARGS in args1
has_kwargs = KWARGS in args1
@@ -1092,7 +1206,7 @@ def match_params(args1, kwargs1, args2, kwargs2):
# We have something different there. If we don't have positional
# arguments on the original call, it can't match.
if not args2:
- # Unless we have just several VARIOUS (which is bizarre, but..).
+ # Unless we have just several ARGS (which is bizarre, but..).
for arg1 in args1:
if arg1 is not ARGS:
return False
@@ -1239,6 +1353,13 @@ class Event(object):
task.restore()
+class ReplayRestoreEvent(Event):
+ """Helper event for tasks which need replay/restore but shouldn't match."""
+
+ def matches(self, path):
+ return False
+
+
class Task(object):
"""Element used to track one specific aspect on an event.
@@ -1281,6 +1402,16 @@ class Task(object):
# --------------------------------------------------------------------
# Task implementations.
+class OnRestoreCaller(Task):
+ """Call a given callback when restoring."""
+
+ def __init__(self, callback):
+ self._callback = callback
+
+ def restore(self):
+ self._callback()
+
+
class PathMatcher(Task):
"""Match the action path against a given path."""
@@ -1500,9 +1631,6 @@ class ProxyReplacer(Task):
self.mock = mock
self.__mocker_replace__ = False
- def matches(self, path):
- return False
-
def replay(self):
global_replace(self.mock.__mocker_object__, self.mock)
@@ -1535,9 +1663,6 @@ class Patcher(Task):
self._monitored = {} # {kind: {id(object): object}}
self._patched = {}
- def matches(self, path):
- return False
-
def is_monitoring(self, obj, kind):
monitored = self._monitored.get(kind)
if monitored:
diff --git a/test.py b/test.py
index f768668..2d9475a 100755
--- a/test.py
+++ b/test.py
@@ -1,5 +1,6 @@
#!/usr/bin/python
import unittest
+import inspect
import sys
import os
import gc
@@ -11,13 +12,13 @@ from mocker import (
PathMatcher, path_matcher_recorder, RunCounter, ImplicitRunCounter,
run_counter_recorder, run_counter_removal_recorder, MockReturner,
mock_returner_recorder, FunctionRunner, Orderer, SpecChecker,
- spec_checker_recorder, match_params, ANY, VARIOUS, SAME, CONTAINS,
- ARGS, KWARGS, MatchError, PathExecuter, ProxyReplacer, Patcher,
- Undefined, PatchedMethod)
+ spec_checker_recorder, match_params, ANY, IS, CONTAINS, IN, ARGS, KWARGS,
+ MatchError, PathExecuter, ProxyReplacer, Patcher, Undefined, PatchedMethod,
+ MockerTestCase, ReplayRestoreEvent, OnRestoreCaller)
class CleanMocker(MockerBase):
- pass
+ """Just a better name for MockerBase in a testing context."""
class IntegrationTest(unittest.TestCase):
@@ -229,6 +230,275 @@ class ExpectTest(unittest.TestCase):
self.assertEquals(obj.attr, 42)
+class MockerTestCaseTest(unittest.TestCase):
+
+ def setUp(self):
+ self.test = MockerTestCase("__init__")
+
+ def test_has_mocker(self):
+ self.assertEquals(type(self.test.mocker), Mocker)
+
+ def test_has_expect(self):
+ self.assertTrue(self.test.expect is expect)
+
+ def test_constructor_is_the_same(self):
+ self.assertEquals(inspect.getargspec(unittest.TestCase.__init__),
+ inspect.getargspec(MockerTestCase.__init__))
+
+ def test_docstring_is_the_same(self):
+ class MyTest(MockerTestCase):
+ def test_method(self):
+ """Hello there!"""
+ self.assertEquals(MyTest("test_method").test_method.__doc__,
+ "Hello there!")
+
+ def test_short_description_is_the_same(self):
+ class MyTest(MockerTestCase):
+ def test_method(self):
+ """Hello there!"""
+ class StandardTest(unittest.TestCase):
+ def test_method(self):
+ """Hello there!"""
+
+ self.assertEquals(MyTest("test_method").shortDescription(),
+ StandardTest("test_method").shortDescription())
+
+ def test_missing_method_raises_the_same_error(self):
+ class MyTest(unittest.TestCase):
+ pass
+
+ try:
+ MyTest("unexistent_method").run()
+ except Exception, e:
+ expected_error = e
+
+ class MyTest(MockerTestCase):
+ pass
+
+ try:
+ MyTest("unexistent_method").run()
+ except Exception, e:
+ self.assertEquals(str(e), str(expected_error))
+ self.assertEquals(type(e), type(expected_error))
+
+ def test_mocker_is_verified_and_restored_after_test_method_is_run(self):
+ calls = []
+ class MyEvent(Event):
+ def verify(self):
+ calls.append("verify")
+ def restore(self):
+ calls.append("restore")
+ class MyTest(MockerTestCase):
+ def test_method(self):
+ self.mocker.add_event(MyEvent())
+ self.mocker.replay()
+ def test_method_raising(self):
+ self.mocker.add_event(MyEvent())
+ self.mocker.replay()
+ raise AssertionError("BOOM!")
+
+ result = unittest.TestResult()
+ MyTest("test_method").run(result)
+
+ self.assertEquals(calls, ["restore", "verify"])
+ self.assertTrue(result.wasSuccessful())
+
+ del calls[:]
+
+ result = unittest.TestResult()
+ MyTest("test_method_raising").run(result)
+
+ self.assertEquals(calls, ["restore"])
+ self.assertEquals(len(result.errors), 0)
+ self.assertEquals(len(result.failures), 1)
+ self.assertTrue("BOOM!" in result.failures[0][1])
+
+ def test_expectation_failure_acts_appropriately(self):
+ class MyTest(MockerTestCase):
+ def test_method(self):
+ mock = self.mocker.mock()
+ mock.x
+ self.mocker.replay()
+
+ result = unittest.TestResult()
+ MyTest("test_method").run(result)
+
+ self.assertEquals(len(result.errors), 0)
+ self.assertEquals(len(result.failures), 1)
+ self.assertTrue("mock.x" in result.failures[0][1])
+
+ def test_fail_unless_is_raises_on_mismatch(self):
+ try:
+ self.test.failUnlessIs([], [])
+ except AssertionError, e:
+ self.assertEquals(str(e), "[] is not []")
+ else:
+ self.fail("AssertionError not raised")
+
+ def test_fail_unless_is_uses_msg(self):
+ try:
+ self.test.failUnlessIs([], [], "oops!")
+ except AssertionError, e:
+ self.assertEquals(str(e), "oops!")
+ else:
+ self.fail("AssertionError not raised")
+
+ def test_fail_unless_is_succeeds(self):
+ obj = []
+ try:
+ self.test.failUnlessIs(obj, obj)
+ except AssertionError:
+ self.fail("AssertionError shouldn't be raised")
+
+ def test_fail_if_is_raises_on_mismatch(self):
+ obj = []
+ try:
+ self.test.failIfIs(obj, obj)
+ except AssertionError, e:
+ self.assertEquals(str(e), "[] is []")
+ else:
+ self.fail("AssertionError not raised")
+
+ def test_fail_if_is_uses_msg(self):
+ obj = []
+ try:
+ self.test.failIfIs(obj, obj, "oops!")
+ except AssertionError, e:
+ self.assertEquals(str(e), "oops!")
+ else:
+ self.fail("AssertionError not raised")
+
+ def test_fail_if_is_succeeds(self):
+ try:
+ self.test.failIfIs([], [])
+ except AssertionError:
+ self.fail("AssertionError shouldn't be raised")
+
+ def test_fail_unless_in_raises_on_mismatch(self):
+ try:
+ self.test.failUnlessIn(1, [])
+ except AssertionError, e:
+ self.assertEquals(str(e), "1 not in []")
+ else:
+ self.fail("AssertionError not raised")
+
+ def test_fail_unless_in_uses_msg(self):
+ try:
+ self.test.failUnlessIn(1, [], "oops!")
+ except AssertionError, e:
+ self.assertEquals(str(e), "oops!")
+ else:
+ self.fail("AssertionError not raised")
+
+ def test_fail_unless_in_succeeds(self):
+ try:
+ self.test.failUnlessIn(1, [1])
+ except AssertionError:
+ self.fail("AssertionError shouldn't be raised")
+
+ def test_fail_if_in_raises_on_mismatch(self):
+ try:
+ self.test.failIfIn(1, [1])
+ except AssertionError, e:
+ self.assertEquals(str(e), "1 in [1]")
+ else:
+ self.fail("AssertionError not raised")
+
+ def test_fail_if_in_uses_msg(self):
+ try:
+ self.test.failIfIn(1, [1], "oops!")
+ except AssertionError, e:
+ self.assertEquals(str(e), "oops!")
+ else:
+ self.fail("AssertionError not raised")
+
+ def test_fail_if_in_succeeds(self):
+ try:
+ self.test.failIfIn(1, [])
+ except AssertionError:
+ self.fail("AssertionError shouldn't be raised")
+
+ def test_fail_unless_approximates_raises_on_mismatch(self):
+ try:
+ self.test.failUnlessApproximates(1, 2, 0.999)
+ except AssertionError, e:
+ self.assertEquals(str(e), "abs(1 - 2) > 0.999")
+ else:
+ self.fail("AssertionError not raised")
+
+ def test_fail_unless_approximates_uses_msg(self):
+ try:
+ self.test.failUnlessApproximates(1, 2, 0.999, "oops!")
+ except AssertionError, e:
+ self.assertEquals(str(e), "oops!")
+ else:
+ self.fail("AssertionError not raised")
+
+ def test_fail_unless_approximates_succeeds(self):
+ try:
+ self.test.failUnlessApproximates(1, 2, 1)
+ except AssertionError:
+ self.fail("AssertionError shouldn't be raised")
+
+ def test_fail_if_approximates_raises_on_mismatch(self):
+ try:
+ self.test.failIfApproximates(1, 2, 1)
+ except AssertionError, e:
+ self.assertEquals(str(e), "abs(1 - 2) <= 1")
+ else:
+ self.fail("AssertionError not raised")
+
+ def test_fail_if_approximates_uses_msg(self):
+ try:
+ self.test.failIfApproximates(1, 2, 1, "oops!")
+ except AssertionError, e:
+ self.assertEquals(str(e), "oops!")
+ else:
+ self.fail("AssertionError not raised")
+
+ def test_fail_if_approximates_succeeds(self):
+ try:
+ self.test.failIfApproximates(1, 2, 0.999)
+ except AssertionError:
+ self.fail("AssertionError shouldn't be raised")
+
+ def test_aliases(self):
+ get_method = MockerTestCase.__dict__.get
+
+ self.assertEquals(get_method("assertIs"),
+ get_method("failUnlessIs"))
+
+ self.assertEquals(get_method("assertIsNot"),
+ get_method("failIfIs"))
+
+ self.assertEquals(get_method("assertIn"),
+ get_method("failUnlessIn"))
+
+ self.assertEquals(get_method("assertNotIn"),
+ get_method("failIfIn"))
+
+ self.assertEquals(get_method("assertApproximates"),
+ get_method("failUnlessApproximates"))
+
+ self.assertEquals(get_method("assertNotApproximates"),
+ get_method("failIfApproximates"))
+
+ def test_twisted_trial_aliases(self):
+ get_method = MockerTestCase.__dict__.get
+
+ self.assertEquals(get_method("assertIdentical"),
+ get_method("assertIs"))
+
+ self.assertEquals(get_method("assertNotIdentical"),
+ get_method("assertIsNot"))
+
+ self.assertEquals(get_method("failUnlessIdentical"),
+ get_method("failUnlessIs"))
+
+ self.assertEquals(get_method("failIfIdentical"),
+ get_method("failIfIs"))
+
+
class MockerTest(unittest.TestCase):
def setUp(self):
@@ -269,6 +539,16 @@ class MockerTest(unittest.TestCase):
self.assertTrue(self.mocker.is_recording())
self.assertEquals(calls, ["replay", "restore"])
+ def test_on_restore(self):
+ calls = []
+ self.mocker.on_restore(lambda: calls.append("callback"))
+ self.mocker.restore()
+ self.assertEquals(calls, [])
+ self.mocker.replay()
+ self.mocker.restore()
+ self.mocker.restore()
+ self.assertEquals(calls, ["callback"])
+
def test_reset(self):
calls = []
event = self.mocker.add_event(Event())
@@ -494,6 +774,7 @@ class MockerTest(unittest.TestCase):
self.assertEquals(proxy.__mocker_spec__, object)
self.assertEquals(proxy.__mocker_name__, "obj")
(event,) = self.mocker.get_events()
+ self.assertEquals(type(event), ReplayRestoreEvent)
(task,) = event.get_tasks()
self.assertEquals(type(task), ProxyReplacer)
self.assertTrue(task.mock is proxy)
@@ -910,6 +1191,7 @@ class MockerTest(unittest.TestCase):
self.assertEquals(mock.__mocker_passthrough__, True)
self.assertEquals(mock.__mocker_spec__, C)
(event,) = self.mocker.get_events()
+ self.assertEquals(type(event), ReplayRestoreEvent)
(task,) = event.get_tasks()
self.assertTrue(task is mock.__mocker_patcher__)
@@ -1307,34 +1589,22 @@ class MatchParamsTest(unittest.TestCase):
self.assertTrue(ANY.matches(42))
self.assertTrue(ANY.matches(object()))
- def test_various_repr(self):
- self.assertEquals(repr(VARIOUS), "VARIOUS")
-
- def test_various_equals(self):
- self.assertEquals(VARIOUS, VARIOUS)
- self.assertNotEquals(VARIOUS, object())
-
- def test_various_matches(self):
- self.assertTrue(VARIOUS.matches(1))
- self.assertTrue(VARIOUS.matches(42))
- self.assertTrue(VARIOUS.matches(object()))
+ def test_is_repr(self):
+ self.assertEquals(repr(IS("obj")), "IS('obj')")
- def test_same_repr(self):
- self.assertEquals(repr(SAME("obj")), "SAME('obj')")
-
- def test_same_equals(self):
+ def test_is_equals(self):
l1 = []
l2 = []
- self.assertNotEquals(SAME(l1), l2)
- self.assertEquals(SAME(l1), SAME(l1))
- self.assertNotEquals(SAME(l1), SAME(l2))
+ self.assertNotEquals(IS(l1), l2)
+ self.assertEquals(IS(l1), IS(l1))
+ self.assertNotEquals(IS(l1), IS(l2))
- def test_same_matches(self):
+ def test_is_matches(self):
l1 = []
l2 = []
- self.assertTrue(SAME(l1).matches(l1))
- self.assertFalse(SAME(l1).matches(l2))
- self.assertFalse(SAME(l1).matches(ANY))
+ self.assertTrue(IS(l1).matches(l1))
+ self.assertFalse(IS(l1).matches(l2))
+ self.assertFalse(IS(l1).matches(ANY))
def test_contains_repr(self):
self.assertEquals(repr(CONTAINS("obj")), "CONTAINS('obj')")
@@ -1355,6 +1625,18 @@ class MatchParamsTest(unittest.TestCase):
return True
self.assertTrue(CONTAINS(1).matches(C()))
+ def test_in_repr(self):
+ self.assertEquals(repr(IN("obj")), "IN('obj')")
+
+ def test_in_equals(self):
+ self.assertEquals(IN([1]), IN([1]))
+ self.assertNotEquals(IN([1]), IN(1))
+
+ def test_in_matches(self):
+ self.assertTrue(IN([1]).matches(1))
+ self.assertFalse(IN([1]).matches([1]))
+ self.assertFalse(IN([1]).matches(object()))
+
def test_normal(self):
self.true((), {}, (), {})
self.true((1, 2), {"a": 3}, (1, 2), {"a": 3})
@@ -1894,6 +2176,17 @@ class EventTest(unittest.TestCase):
self.assertEquals(calls, ["task1", "task2"])
+class ReplayRestoreEventTest(unittest.TestCase):
+
+ def setUp(self):
+ self.event = ReplayRestoreEvent()
+
+ def test_never_matches(self):
+ self.assertEquals(self.event.matches(None), False)
+ self.event.add_task(Task())
+ self.assertEquals(self.event.matches(None), False)
+
+
class TaskTest(unittest.TestCase):
def setUp(self):
@@ -1915,6 +2208,25 @@ class TaskTest(unittest.TestCase):
self.assertEquals(self.task.restore(), None)
+class OnRestoreCallerTest(unittest.TestCase):
+
+ def setUp(self):
+ self.mocker = CleanMocker()
+ self.mock = self.mocker.mock()
+
+ def test_is_task(self):
+ self.assertTrue(isinstance(OnRestoreCaller(None), Task))
+
+ def test_restore(self):
+ calls = []
+ task = OnRestoreCaller(lambda: calls.append("callback"))
+ self.assertEquals(calls, [])
+ task.restore()
+ self.assertEquals(calls, ["callback"])
+ task.restore()
+ self.assertEquals(calls, ["callback", "callback"])
+
+
class PathMatcherTest(unittest.TestCase):
def setUp(self):
@@ -2445,9 +2757,6 @@ class ProxyReplacerTest(unittest.TestCase):
task = ProxyReplacer(mock)
self.assertEquals(task.mock, mock)
- def test_matches_nothing(self):
- self.assertFalse(self.task.matches(None))
-
def test_defaults_to_not_installed(self):
import calendar
self.assertEquals(type(calendar), ModuleType)
@@ -2552,9 +2861,6 @@ class PatcherTest(unittest.TestCase):
def test_is_task(self):
self.assertTrue(isinstance(Patcher(), Task))
- def test_matches_nothing(self):
- self.assertFalse(self.patcher.matches(None))
-
def test_is_monitoring_unseen_class_kind(self):
self.assertFalse(self.patcher.is_monitoring(self.C, "kind"))