168 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			168 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # Copyright (c) 2010 Twisted Matrix Laboratories.
 | |
| # See LICENSE for details.
 | |
| 
 | |
| """Tests for testtools.monkey."""
 | |
| 
 | |
| from testtools import TestCase
 | |
| from testtools.matchers import MatchesException, Raises
 | |
| from testtools.monkey import MonkeyPatcher, patch
 | |
| 
 | |
| 
 | |
| class TestObj:
 | |
| 
 | |
|     def __init__(self):
 | |
|         self.foo = 'foo value'
 | |
|         self.bar = 'bar value'
 | |
|         self.baz = 'baz value'
 | |
| 
 | |
| 
 | |
| class MonkeyPatcherTest(TestCase):
 | |
|     """
 | |
|     Tests for 'MonkeyPatcher' monkey-patching class.
 | |
|     """
 | |
| 
 | |
|     def setUp(self):
 | |
|         super(MonkeyPatcherTest, self).setUp()
 | |
|         self.test_object = TestObj()
 | |
|         self.original_object = TestObj()
 | |
|         self.monkey_patcher = MonkeyPatcher()
 | |
| 
 | |
|     def test_empty(self):
 | |
|         # A monkey patcher without patches doesn't change a thing.
 | |
|         self.monkey_patcher.patch()
 | |
| 
 | |
|         # We can't assert that all state is unchanged, but at least we can
 | |
|         # check our test object.
 | |
|         self.assertEquals(self.original_object.foo, self.test_object.foo)
 | |
|         self.assertEquals(self.original_object.bar, self.test_object.bar)
 | |
|         self.assertEquals(self.original_object.baz, self.test_object.baz)
 | |
| 
 | |
|     def test_construct_with_patches(self):
 | |
|         # Constructing a 'MonkeyPatcher' with patches adds all of the given
 | |
|         # patches to the patch list.
 | |
|         patcher = MonkeyPatcher((self.test_object, 'foo', 'haha'),
 | |
|                                 (self.test_object, 'bar', 'hehe'))
 | |
|         patcher.patch()
 | |
|         self.assertEquals('haha', self.test_object.foo)
 | |
|         self.assertEquals('hehe', self.test_object.bar)
 | |
|         self.assertEquals(self.original_object.baz, self.test_object.baz)
 | |
| 
 | |
|     def test_patch_existing(self):
 | |
|         # Patching an attribute that exists sets it to the value defined in the
 | |
|         # patch.
 | |
|         self.monkey_patcher.add_patch(self.test_object, 'foo', 'haha')
 | |
|         self.monkey_patcher.patch()
 | |
|         self.assertEquals(self.test_object.foo, 'haha')
 | |
| 
 | |
|     def test_patch_non_existing(self):
 | |
|         # Patching a non-existing attribute sets it to the value defined in
 | |
|         # the patch.
 | |
|         self.monkey_patcher.add_patch(self.test_object, 'doesntexist', 'value')
 | |
|         self.monkey_patcher.patch()
 | |
|         self.assertEquals(self.test_object.doesntexist, 'value')
 | |
| 
 | |
|     def test_restore_non_existing(self):
 | |
|         # Restoring a value that didn't exist before the patch deletes the
 | |
|         # value.
 | |
|         self.monkey_patcher.add_patch(self.test_object, 'doesntexist', 'value')
 | |
|         self.monkey_patcher.patch()
 | |
|         self.monkey_patcher.restore()
 | |
|         marker = object()
 | |
|         self.assertIs(marker, getattr(self.test_object, 'doesntexist', marker))
 | |
| 
 | |
|     def test_patch_already_patched(self):
 | |
|         # Adding a patch for an object and attribute that already have a patch
 | |
|         # overrides the existing patch.
 | |
|         self.monkey_patcher.add_patch(self.test_object, 'foo', 'blah')
 | |
|         self.monkey_patcher.add_patch(self.test_object, 'foo', 'BLAH')
 | |
|         self.monkey_patcher.patch()
 | |
|         self.assertEquals(self.test_object.foo, 'BLAH')
 | |
|         self.monkey_patcher.restore()
 | |
|         self.assertEquals(self.test_object.foo, self.original_object.foo)
 | |
| 
 | |
|     def test_restore_twice_is_a_no_op(self):
 | |
|         # Restoring an already-restored monkey patch is a no-op.
 | |
|         self.monkey_patcher.add_patch(self.test_object, 'foo', 'blah')
 | |
|         self.monkey_patcher.patch()
 | |
|         self.monkey_patcher.restore()
 | |
|         self.assertEquals(self.test_object.foo, self.original_object.foo)
 | |
|         self.monkey_patcher.restore()
 | |
|         self.assertEquals(self.test_object.foo, self.original_object.foo)
 | |
| 
 | |
|     def test_run_with_patches_decoration(self):
 | |
|         # run_with_patches runs the given callable, passing in all arguments
 | |
|         # and keyword arguments, and returns the return value of the callable.
 | |
|         log = []
 | |
| 
 | |
|         def f(a, b, c=None):
 | |
|             log.append((a, b, c))
 | |
|             return 'foo'
 | |
| 
 | |
|         result = self.monkey_patcher.run_with_patches(f, 1, 2, c=10)
 | |
|         self.assertEquals('foo', result)
 | |
|         self.assertEquals([(1, 2, 10)], log)
 | |
| 
 | |
|     def test_repeated_run_with_patches(self):
 | |
|         # We can call the same function with run_with_patches more than
 | |
|         # once. All patches apply for each call.
 | |
|         def f():
 | |
|             return (self.test_object.foo, self.test_object.bar,
 | |
|                     self.test_object.baz)
 | |
| 
 | |
|         self.monkey_patcher.add_patch(self.test_object, 'foo', 'haha')
 | |
|         result = self.monkey_patcher.run_with_patches(f)
 | |
|         self.assertEquals(
 | |
|             ('haha', self.original_object.bar, self.original_object.baz),
 | |
|             result)
 | |
|         result = self.monkey_patcher.run_with_patches(f)
 | |
|         self.assertEquals(
 | |
|             ('haha', self.original_object.bar, self.original_object.baz),
 | |
|             result)
 | |
| 
 | |
|     def test_run_with_patches_restores(self):
 | |
|         # run_with_patches restores the original values after the function has
 | |
|         # executed.
 | |
|         self.monkey_patcher.add_patch(self.test_object, 'foo', 'haha')
 | |
|         self.assertEquals(self.original_object.foo, self.test_object.foo)
 | |
|         self.monkey_patcher.run_with_patches(lambda: None)
 | |
|         self.assertEquals(self.original_object.foo, self.test_object.foo)
 | |
| 
 | |
|     def test_run_with_patches_restores_on_exception(self):
 | |
|         # run_with_patches restores the original values even when the function
 | |
|         # raises an exception.
 | |
|         def _():
 | |
|             self.assertEquals(self.test_object.foo, 'haha')
 | |
|             self.assertEquals(self.test_object.bar, 'blahblah')
 | |
|             raise RuntimeError("Something went wrong!")
 | |
| 
 | |
|         self.monkey_patcher.add_patch(self.test_object, 'foo', 'haha')
 | |
|         self.monkey_patcher.add_patch(self.test_object, 'bar', 'blahblah')
 | |
| 
 | |
|         self.assertThat(lambda:self.monkey_patcher.run_with_patches(_),
 | |
|             Raises(MatchesException(RuntimeError("Something went wrong!"))))
 | |
|         self.assertEquals(self.test_object.foo, self.original_object.foo)
 | |
|         self.assertEquals(self.test_object.bar, self.original_object.bar)
 | |
| 
 | |
| 
 | |
| class TestPatchHelper(TestCase):
 | |
| 
 | |
|     def test_patch_patches(self):
 | |
|         # patch(obj, name, value) sets obj.name to value.
 | |
|         test_object = TestObj()
 | |
|         patch(test_object, 'foo', 42)
 | |
|         self.assertEqual(42, test_object.foo)
 | |
| 
 | |
|     def test_patch_returns_cleanup(self):
 | |
|         # patch(obj, name, value) returns a nullary callable that restores obj
 | |
|         # to its original state when run.
 | |
|         test_object = TestObj()
 | |
|         original = test_object.foo
 | |
|         cleanup = patch(test_object, 'foo', 42)
 | |
|         cleanup()
 | |
|         self.assertEqual(original, test_object.foo)
 | |
| 
 | |
| 
 | |
| def test_suite():
 | |
|     from unittest import TestLoader
 | |
|     return TestLoader().loadTestsFromName(__name__)
 | 
