Уведомления

Группа в Telegram: @pythonsu

#1 Фев. 10, 2011 18:47:24

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

TestCase и time.sleep

Kogrom
Я понимаю так, что юнит-тесты и код, который они тестируют сильно взаимосвязаны, так как:
1. Юнит-тесты дают примеры использования кода. То есть получается своеобразная живая документация. Поэтому пользователю-программисту они очень пригодятся. Без них код будет беднее.
2. Юнит-тесты формируют из кода некий недофрейворк (библиотеку, пакет - называйте как хотите). Как они это делают? Проверяют классы на вторичное использование. И это хорошо. Посмотрите на библиотечные функции и классы Python-а - они избыточны для конкретного программиста, но никто особо не страдает. Поэтому не вижу ничего плохого в том, что юнит-тест диктует коду каким ему быть.
Вторичное использование - это правда. Применение тестов позволяет еще раз взглянуть на дизайн системы под новым углом.

Тем не менее я не считаю, что вводить малопонятные крючки, требующиеся только лишь для выполнения тестового кода - хорошая практика.
Если же тесты помогают перепроектировать систему так, чтобы она была не столь монолитна и получила (практически бесплатно) большую гибкость - двумя руками
“за”!

С подходом к тестам как “живой документации” не всё так просто. Изучение чужих библиотек мне подсказывает, что хорошее тестовое покрытие слабо совмещается с ясными и понятными тестами, легко читаемыми сторонним разработчиком.

Для проверки я посмотрел тестовые пакеты для Питона и twisted (с их тестами довольно хорошо знаком) и Пирамиды (новой поделки, имеющей замечательное тестовое покрытие).

По их тестам нельзя изучать систему. Нужно читать исходники и документацию.
Если “что-то пошло не так” - ответ скорее найдется в исходниках, чем в тестах.

Другое дело - работа над изменением библиотеки. Здесь тесты на своём, законном месте. Они замечательно “дают по рукам” и помогают выявить глубокие взаимосвязи, как правило не интересные внешнему разработчику.

Про избыточность библиотечных классов и функций Питона - откровенно говоря, не понял. Как по мне - наоборот. Стандартная библиотека успешно скрывает особенности реализации, давая пользователю простой и понятный интерфейс. Ляпы случаются - но тенденция всё же прослеживается.



Офлайн

#2 Фев. 10, 2011 21:54:03

Kogrom
От:
Зарегистрирован: 2009-12-03
Сообщения: 160
Репутация: +  0  -
Профиль   Отправить e-mail  

TestCase и time.sleep

Андрей Светлов
Про избыточность библиотечных классов и функций Питона - откровенно говоря, не понял. Как по мне - наоборот. Стандартная библиотека успешно скрывает особенности реализации, давая пользователю простой и понятный интерфейс. Ляпы случаются - но тенденция всё же прослеживается.
Я не про ляпы говорил, не про сложный интерфейс. Взять какой-нибудь модуль, random, например. Имеется куча разнообразных функций, из которых какой-нибудь конкретный программист использует 3-5. Если вести статистику, то может оказаться, что какой-нибудь randrange используют 3 программиста в мире (но и они легко найдут замену). Но никому дела нет - потенциально может быть востребовано. Или есть у разработчиков понятные методы оценки нужности функций в библиотеке?

Возможно, проблема в способе отделения “малопонятного крючка” от параметра, который может быть востребован. Так в примере с def can_show(self, date=None) можно сказать, что тут есть возможность задать дату не нашего компьютера, а удалённого сервера, например. Но неизвестно, будет ли кто-то использовать эту возможность.



Офлайн

#3 Фев. 10, 2011 22:02:47

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

TestCase и time.sleep

Kogrom
проблема в способе отделения “малопонятного крючка” от параметра, который может быть востребован. Так в примере с def can_show(self, date=None) можно сказать, что тут есть возможность задать дату не нашего компьютера, а удалённого сервера, например. Но неизвестно, будет ли кто-то использовать эту возможность.
Если `can_show` и класс `Billing` вообще разрабатываются так, чтобы полностью не зависеть от datetime.now() по дизайну - это хорошо, к такому нужно стремиться. Если вы придумываете новый непротиворечивый сценарий работы, удовлетворяющий тестам и здравому смыслу - почему нет?
А когда каждый метод обрастает несколькими параметрами, необходимыми только для тестов - плохо.

Различие нужно проводить каждый раз заново, смотря на конкретный код.



Офлайн

#4 Фев. 10, 2011 22:08:23

Kogrom
От:
Зарегистрирован: 2009-12-03
Сообщения: 160
Репутация: +  0  -
Профиль   Отправить e-mail  

TestCase и time.sleep

Всё, до меня дошло :)



Офлайн

#5 Фев. 10, 2011 22:17:42

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

TestCase и time.sleep

Рад за вас. До меня доходило очень долго - и не уверен, что в полной мере осознал :)



Офлайн

#6 Фев. 11, 2011 15:31:51

Kogrom
От:
Зарегистрирован: 2009-12-03
Сообщения: 160
Репутация: +  0  -
Профиль   Отправить e-mail  

TestCase и time.sleep

Я надеюсь, дошло то, что собеседник хотел сказать про “малопонятные крючки”. Хотя для полной ясности надо бы примеры, но в теории понятно.

До полного понимания TDD и до ясного дизайна мне ещё далеко. В Python ещё приемлемо, а в C++ быстро скатываюсь в какую-то legacy-процедурщину…



Офлайн

#7 Фев. 12, 2011 09:33:18

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

TestCase и time.sleep

Kogrom, я попытаюсь изложить все мои соображения чётко и ясно, создавая по ходу дела нужные примеры.
Не могу обещать, что сделаю это скоро. Но задумка интересная.
Этот топик наткнулся на неочевидную (хоть и распространенную) проблему юнит-тестирования.
Научиться писать self.assertEqual легко, а тестировать живое приложение - гораздо сложнее.



Офлайн

#8 Фев. 16, 2011 16:39:43

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

TestCase и time.sleep

Обещал расписать подробно - вот: http://asvetlov.blogspot.com/2011/02/funny-unittests.html



Офлайн

#9 Фев. 16, 2011 21:58:26

Kogrom
От:
Зарегистрирован: 2009-12-03
Сообщения: 160
Репутация: +  0  -
Профиль   Отправить e-mail  

TestCase и time.sleep

Андрей Светлов
Обещал расписать подробно - вот: http://asvetlov.blogspot.com/2011/02/funny-unittests.html
Упущен ещё один способ (хотя можно его считать разновидностью третьего):

def _test_html_fresh(self, rst_time, html_time):
return rst_time <= html_time

@property
def is_html_fresh(self):
if not os.path.exists(self.html_path):
return False
rst_time = os.path.getmtime(self.full_path)
html_time = os.path.getmtime(self.html_path)
return self._test_html_fresh(rst_time, html_time)
Фактически при всех подделках мы тестируем вот этот _test_html_fresh. Так почему бы его просто не вынести и не потестировать? Я придумал не очень хорошее имя для этого метода. Возможно, если его подобрать получше, то метод можно было бы сделать даже открытым :)



Отредактировано (Фев. 16, 2011 22:24:05)

Офлайн

#10 Фев. 16, 2011 22:52:36

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

TestCase и time.sleep

Как мне кажется, тесты всё же должны работать в первую очередь с public interface.

Сам по себе _test_html_fresh не имеет смысла (по крайней мере в моем случае) - это по сути staticmethod, так как не может вызывать методы экземпляра (потенциально небезопасные). Попробуйте написать аналог для refresh_html.
Приходится полагаться на то, что is_html_fresh не может ошибаться, а все беды только от _test_html_fresh. Таким образом опять отходим от полного покрытия тестами.
Одно дело - когда эта ситуация объясняется недостаточными усилиями программиста.
И совершенно другое - если мы сознательно строим изначально ущербный подход.
К тому же настоятельно не рекомендую использовать третий способ, а вариантов это сделать вопреки всему - миллион.

Подмена FileSystem всяко лучше и удобней.



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version