Скачать презентацию
Идет загрузка презентации. Пожалуйста, подождите
Презентация была опубликована 10 лет назад пользователемСтепан Федин
1 Mock-объекты mock (англ.) – ложный, фиктивный, мнимый, фальшивый, поддельный
2 Первый пример Мы хотим протестировать функцию f: def f(x): return g(x) * g(x)
3 НО: 1)Функция g еще не написана
4 ИЛИ: 2) Функция g работает недетерминировано: def g(x): return randint(5 * x)
5 ИЛИ: 3) Функция g слишком сложна, в ней тоже могут быть ошибки. Хотим протестировать f независимо
6 ИЛИ: 4) Функция g имеет нежелательные при тестировании побочные эффекты: def g(x): file = open(1.txt, w) file.write(blablabla)
7 Простейшее решение Пишем заглушку (stub): def g(x): return 5 ИДЕЯ: заменить настоящую функцию g на более удобную при тестировании
8 Более сложный пример def f(x): if x > 0 and x < 10: return g(x) elif x
9 Что хочется протестировать? Требуется убедиться, что функция f вызывает функцию g только в нужных случаях и нужное количество раз. ИДЕЯ: Наша фальшивая g не только возвращает фиксированное значение, но и запоминает информацию о своих вызовах.
10 Что для этого нужно? 1)Использовать g как объект (хранить состояние) 2)Чтобы объект можно было вызвать – () – он должен быть callable
11 Как это должно выглядеть? g = … f(5) g.assert_called_once_with(5) f(-5) g.assert_any_call(5) g.assert_any_call(-5)
12 Стандартный модуль unittest.mock (начиная с python3.3) from unittest.mock import Mock g = Mock(return_value = 5) …
13 Мокаем метод объекта def is_empty(group): return len(group.members()) == 0 group1 = Group() group1.members = Mock(return_value= [aaa, bbb, ccc]) is_empty(group1) group1.members.assert_called_with()
14 Мокаем объект group1 = Mock() group1.members.return_value = [aaa, bbb, ccc] Все необходимые методы/поля создаются на лету: group1.count()
15 НО: mock.__str__.return_value = foo вызовет исключение magic-методы (__xxx__) Mock не создает (они часто используются неявно, например, __str__, __eq__ и их автоматическое переопределение не всегда желательно)
16 MagicMock Аналог Mock, дополнительно позволяющий создавать magic-методы from unittest.mock import MagicMock m = MagicMock() m.__str__.return_value = 'foo' print(m) Выведет foo
17 Объекты из стандартных библиотек …тоже можно мокать: from unittest.mock import Mock import random random.randint = Mock(return_value = 100) print(random.randint(10))
18 Мокать можно всё from unittest.mock import Mock print = Mock() print('***')
19 Mock-объект хранит историю вызовов >>> mock = Mock(return_value=None) >>> mock() >>> mock(3, 4) >>> mock(key='fish', next='w00t!') >>> mock.call_args_list [call(), call(3, 4), call(key='fish', next='w00t!')]
20 …которую можно сравнивать с ожидаемыми значениями [call(), call(3, 4), call(key='fish', next='w00t!')] >>> expected = [(), ((3, 4),), ({'key':'fish', 'next':'w00t!'},)] >>> mock.call_args_list == expected True
21 Если return_value не определено … то возвращается Mock-объект: >>> open = Mock() >>> f = open("1.txt") >>> print(f) Для его методов также создаются новые Мock- объекты: >>> s = f.read() >>> print(s) >> print(f) Для его методов также создаются новые Мock- объекты: >>> s = f.read() >>> print(s)">
22 НО! from unittest.mock import Mock open = Mock() with open("1.txt") as f: s = f.read() вызовет исключение: AttributeError: __exit__
23 Замена на MagicMock лечит но проблемы остаются… Решение из коробки: from unittest.mock import mock_open open = mock_open(read_data='To be or...') with open("1.txt") as f: print(f.read()) print(open.mock_calls)
24 Выведет To be or... [call('1.txt'), call().__enter__(), call().read(), call().__exit__(None, None, None)]
25 Преимущества mock_open 1)Корректно работает и вместо отдельного open, и в конструкции с with 2)Необязательный параметр read_data (только для read!!!) 3)поддерживает только стандартный методы для файлов и выдает исключения для остальных: >>> f.aaa() AttributeError: Mock object has no attribute 'aaa'
26 patch func.py: def f(x): return g(x) * g(x) def g(x):...
27 func_test.py import unittest from func import f class FTest(unittest.TestCase): def test_f(self): result = f(5) self.assertEqual(result, 9) if __name__ == '__main__': unittest.main()
28 patch from unittest.mock import return_value = 3) def test_f(self, mock_g): result = f(5) self.assertEqual(result, 9)
29 Преимущества Mock-объектов 1)Независимое тестирование одного метода или класса 2)Скорость тестирования (не выполняется лишний код) 3)Стимулирует к правильному проектированию 4)Избавление от недетерминированного поведения 5)Генерация сложно воспроизводимых в реальных условиях ошибок 6)Запись и анализ логов вызовов функций
Еще похожие презентации в нашем архиве:
© 2024 MyShared Inc.
All rights reserved.