1import unittest 2from unittest import mock 3 4 5class SampleObject: 6 def __init__(self): 7 self.attr_sample1 = 1 8 self.attr_sample2 = 1 9 10 def method_sample1(self): 11 pass 12 13 def method_sample2(self): 14 pass 15 16 17class TestSealable(unittest.TestCase): 18 19 def test_attributes_return_more_mocks_by_default(self): 20 m = mock.Mock() 21 22 self.assertIsInstance(m.test, mock.Mock) 23 self.assertIsInstance(m.test(), mock.Mock) 24 self.assertIsInstance(m.test().test2(), mock.Mock) 25 26 def test_new_attributes_cannot_be_accessed_on_seal(self): 27 m = mock.Mock() 28 29 mock.seal(m) 30 with self.assertRaises(AttributeError): 31 m.test 32 with self.assertRaises(AttributeError): 33 m() 34 35 def test_new_attributes_cannot_be_set_on_seal(self): 36 m = mock.Mock() 37 38 mock.seal(m) 39 with self.assertRaises(AttributeError): 40 m.test = 1 41 42 def test_existing_attributes_can_be_set_on_seal(self): 43 m = mock.Mock() 44 m.test.test2 = 1 45 46 mock.seal(m) 47 m.test.test2 = 2 48 self.assertEqual(m.test.test2, 2) 49 50 def test_new_attributes_cannot_be_set_on_child_of_seal(self): 51 m = mock.Mock() 52 m.test.test2 = 1 53 54 mock.seal(m) 55 with self.assertRaises(AttributeError): 56 m.test.test3 = 1 57 58 def test_existing_attributes_allowed_after_seal(self): 59 m = mock.Mock() 60 61 m.test.return_value = 3 62 63 mock.seal(m) 64 self.assertEqual(m.test(), 3) 65 66 def test_initialized_attributes_allowed_after_seal(self): 67 m = mock.Mock(test_value=1) 68 69 mock.seal(m) 70 self.assertEqual(m.test_value, 1) 71 72 def test_call_on_sealed_mock_fails(self): 73 m = mock.Mock() 74 75 mock.seal(m) 76 with self.assertRaises(AttributeError): 77 m() 78 79 def test_call_on_defined_sealed_mock_succeeds(self): 80 m = mock.Mock(return_value=5) 81 82 mock.seal(m) 83 self.assertEqual(m(), 5) 84 85 def test_seals_recurse_on_added_attributes(self): 86 m = mock.Mock() 87 88 m.test1.test2().test3 = 4 89 90 mock.seal(m) 91 self.assertEqual(m.test1.test2().test3, 4) 92 with self.assertRaises(AttributeError): 93 m.test1.test2().test4 94 with self.assertRaises(AttributeError): 95 m.test1.test3 96 97 def test_seals_recurse_on_magic_methods(self): 98 m = mock.MagicMock() 99 100 m.test1.test2["a"].test3 = 4 101 m.test1.test3[2:5].test3 = 4 102 103 mock.seal(m) 104 self.assertEqual(m.test1.test2["a"].test3, 4) 105 self.assertEqual(m.test1.test2[2:5].test3, 4) 106 with self.assertRaises(AttributeError): 107 m.test1.test2["a"].test4 108 with self.assertRaises(AttributeError): 109 m.test1.test3[2:5].test4 110 111 def test_seals_dont_recurse_on_manual_attributes(self): 112 m = mock.Mock(name="root_mock") 113 114 m.test1.test2 = mock.Mock(name="not_sealed") 115 m.test1.test2.test3 = 4 116 117 mock.seal(m) 118 self.assertEqual(m.test1.test2.test3, 4) 119 m.test1.test2.test4 # Does not raise 120 m.test1.test2.test4 = 1 # Does not raise 121 122 def test_integration_with_spec_att_definition(self): 123 """You are not restricted when using mock with spec""" 124 m = mock.Mock(SampleObject) 125 126 m.attr_sample1 = 1 127 m.attr_sample3 = 3 128 129 mock.seal(m) 130 self.assertEqual(m.attr_sample1, 1) 131 self.assertEqual(m.attr_sample3, 3) 132 with self.assertRaises(AttributeError): 133 m.attr_sample2 134 135 def test_integration_with_spec_method_definition(self): 136 """You need to defin the methods, even if they are in the spec""" 137 m = mock.Mock(SampleObject) 138 139 m.method_sample1.return_value = 1 140 141 mock.seal(m) 142 self.assertEqual(m.method_sample1(), 1) 143 with self.assertRaises(AttributeError): 144 m.method_sample2() 145 146 def test_integration_with_spec_method_definition_respects_spec(self): 147 """You cannot define methods out of the spec""" 148 m = mock.Mock(SampleObject) 149 150 with self.assertRaises(AttributeError): 151 m.method_sample3.return_value = 3 152 153 def test_sealed_exception_has_attribute_name(self): 154 m = mock.Mock() 155 156 mock.seal(m) 157 with self.assertRaises(AttributeError) as cm: 158 m.SECRETE_name 159 self.assertIn("SECRETE_name", str(cm.exception)) 160 161 def test_attribute_chain_is_maintained(self): 162 m = mock.Mock(name="mock_name") 163 m.test1.test2.test3.test4 164 165 mock.seal(m) 166 with self.assertRaises(AttributeError) as cm: 167 m.test1.test2.test3.test4.boom 168 self.assertIn("mock_name.test1.test2.test3.test4.boom", str(cm.exception)) 169 170 def test_call_chain_is_maintained(self): 171 m = mock.Mock() 172 m.test1().test2.test3().test4 173 174 mock.seal(m) 175 with self.assertRaises(AttributeError) as cm: 176 m.test1().test2.test3().test4() 177 self.assertIn("mock.test1().test2.test3().test4", str(cm.exception)) 178 179 180if __name__ == "__main__": 181 unittest.main() 182