1import unittest 2from unittest import mock 3 4 5class SampleObject: 6 7 def method_sample1(self): pass 8 9 def method_sample2(self): pass 10 11 12class TestSealable(unittest.TestCase): 13 14 def test_attributes_return_more_mocks_by_default(self): 15 m = mock.Mock() 16 17 self.assertIsInstance(m.test, mock.Mock) 18 self.assertIsInstance(m.test(), mock.Mock) 19 self.assertIsInstance(m.test().test2(), mock.Mock) 20 21 def test_new_attributes_cannot_be_accessed_on_seal(self): 22 m = mock.Mock() 23 24 mock.seal(m) 25 with self.assertRaises(AttributeError): 26 m.test 27 with self.assertRaises(AttributeError): 28 m() 29 30 def test_new_attributes_cannot_be_set_on_seal(self): 31 m = mock.Mock() 32 33 mock.seal(m) 34 with self.assertRaises(AttributeError): 35 m.test = 1 36 37 def test_existing_attributes_can_be_set_on_seal(self): 38 m = mock.Mock() 39 m.test.test2 = 1 40 41 mock.seal(m) 42 m.test.test2 = 2 43 self.assertEqual(m.test.test2, 2) 44 45 def test_new_attributes_cannot_be_set_on_child_of_seal(self): 46 m = mock.Mock() 47 m.test.test2 = 1 48 49 mock.seal(m) 50 with self.assertRaises(AttributeError): 51 m.test.test3 = 1 52 53 def test_existing_attributes_allowed_after_seal(self): 54 m = mock.Mock() 55 56 m.test.return_value = 3 57 58 mock.seal(m) 59 self.assertEqual(m.test(), 3) 60 61 def test_initialized_attributes_allowed_after_seal(self): 62 m = mock.Mock(test_value=1) 63 64 mock.seal(m) 65 self.assertEqual(m.test_value, 1) 66 67 def test_call_on_sealed_mock_fails(self): 68 m = mock.Mock() 69 70 mock.seal(m) 71 with self.assertRaises(AttributeError): 72 m() 73 74 def test_call_on_defined_sealed_mock_succeeds(self): 75 m = mock.Mock(return_value=5) 76 77 mock.seal(m) 78 self.assertEqual(m(), 5) 79 80 def test_seals_recurse_on_added_attributes(self): 81 m = mock.Mock() 82 83 m.test1.test2().test3 = 4 84 85 mock.seal(m) 86 self.assertEqual(m.test1.test2().test3, 4) 87 with self.assertRaises(AttributeError): 88 m.test1.test2().test4 89 with self.assertRaises(AttributeError): 90 m.test1.test3 91 92 def test_seals_recurse_on_magic_methods(self): 93 m = mock.MagicMock() 94 95 m.test1.test2["a"].test3 = 4 96 m.test1.test3[2:5].test3 = 4 97 98 mock.seal(m) 99 self.assertEqual(m.test1.test2["a"].test3, 4) 100 self.assertEqual(m.test1.test2[2:5].test3, 4) 101 with self.assertRaises(AttributeError): 102 m.test1.test2["a"].test4 103 with self.assertRaises(AttributeError): 104 m.test1.test3[2:5].test4 105 106 def test_seals_dont_recurse_on_manual_attributes(self): 107 m = mock.Mock(name="root_mock") 108 109 m.test1.test2 = mock.Mock(name="not_sealed") 110 m.test1.test2.test3 = 4 111 112 mock.seal(m) 113 self.assertEqual(m.test1.test2.test3, 4) 114 m.test1.test2.test4 # Does not raise 115 m.test1.test2.test4 = 1 # Does not raise 116 117 def test_integration_with_spec_att_definition(self): 118 """You are not restricted when using mock with spec""" 119 m = mock.Mock(SampleObject) 120 121 m.attr_sample1 = 1 122 m.attr_sample3 = 3 123 124 mock.seal(m) 125 self.assertEqual(m.attr_sample1, 1) 126 self.assertEqual(m.attr_sample3, 3) 127 with self.assertRaises(AttributeError): 128 m.attr_sample2 129 130 def test_integration_with_spec_method_definition(self): 131 """You need to define the methods, even if they are in the spec""" 132 m = mock.Mock(SampleObject) 133 134 m.method_sample1.return_value = 1 135 136 mock.seal(m) 137 self.assertEqual(m.method_sample1(), 1) 138 with self.assertRaises(AttributeError): 139 m.method_sample2() 140 141 def test_integration_with_spec_method_definition_respects_spec(self): 142 """You cannot define methods out of the spec""" 143 m = mock.Mock(SampleObject) 144 145 with self.assertRaises(AttributeError): 146 m.method_sample3.return_value = 3 147 148 def test_sealed_exception_has_attribute_name(self): 149 m = mock.Mock() 150 151 mock.seal(m) 152 with self.assertRaises(AttributeError) as cm: 153 m.SECRETE_name 154 self.assertIn("SECRETE_name", str(cm.exception)) 155 156 def test_attribute_chain_is_maintained(self): 157 m = mock.Mock(name="mock_name") 158 m.test1.test2.test3.test4 159 160 mock.seal(m) 161 with self.assertRaises(AttributeError) as cm: 162 m.test1.test2.test3.test4.boom 163 self.assertIn("mock_name.test1.test2.test3.test4.boom", str(cm.exception)) 164 165 def test_call_chain_is_maintained(self): 166 m = mock.Mock() 167 m.test1().test2.test3().test4 168 169 mock.seal(m) 170 with self.assertRaises(AttributeError) as cm: 171 m.test1().test2.test3().test4() 172 self.assertIn("mock.test1().test2.test3().test4", str(cm.exception)) 173 174 def test_seal_with_autospec(self): 175 # https://bugs.python.org/issue45156 176 class Foo: 177 foo = 0 178 def bar1(self): 179 return 1 180 def bar2(self): 181 return 2 182 183 class Baz: 184 baz = 3 185 def ban(self): 186 return 4 187 188 for spec_set in (True, False): 189 with self.subTest(spec_set=spec_set): 190 foo = mock.create_autospec(Foo, spec_set=spec_set) 191 foo.bar1.return_value = 'a' 192 foo.Baz.ban.return_value = 'b' 193 194 mock.seal(foo) 195 196 self.assertIsInstance(foo.foo, mock.NonCallableMagicMock) 197 self.assertIsInstance(foo.bar1, mock.MagicMock) 198 self.assertIsInstance(foo.bar2, mock.MagicMock) 199 self.assertIsInstance(foo.Baz, mock.MagicMock) 200 self.assertIsInstance(foo.Baz.baz, mock.NonCallableMagicMock) 201 self.assertIsInstance(foo.Baz.ban, mock.MagicMock) 202 203 self.assertEqual(foo.bar1(), 'a') 204 foo.bar1.return_value = 'new_a' 205 self.assertEqual(foo.bar1(), 'new_a') 206 self.assertEqual(foo.Baz.ban(), 'b') 207 foo.Baz.ban.return_value = 'new_b' 208 self.assertEqual(foo.Baz.ban(), 'new_b') 209 210 with self.assertRaises(TypeError): 211 foo.foo() 212 with self.assertRaises(AttributeError): 213 foo.bar = 1 214 with self.assertRaises(AttributeError): 215 foo.bar2() 216 217 foo.bar2.return_value = 'bar2' 218 self.assertEqual(foo.bar2(), 'bar2') 219 220 with self.assertRaises(AttributeError): 221 foo.missing_attr 222 with self.assertRaises(AttributeError): 223 foo.missing_attr = 1 224 with self.assertRaises(AttributeError): 225 foo.missing_method() 226 with self.assertRaises(TypeError): 227 foo.Baz.baz() 228 with self.assertRaises(AttributeError): 229 foo.Baz.missing_attr 230 with self.assertRaises(AttributeError): 231 foo.Baz.missing_attr = 1 232 with self.assertRaises(AttributeError): 233 foo.Baz.missing_method() 234 235 236if __name__ == "__main__": 237 unittest.main() 238