Статьи

Насмешка раздражающе трудно получить право

Насмешка важна для модульного тестирования.

Однако.

Это также досадно трудно получить право. 

Если мы не до конца на сто процентов ясно понимаем, что мы высмеиваем, мы просто канонизируем любые глупые предположения в ложные объекты, которые на самом деле не   работают. Они работают в том смысле, что они не аварийно завершают работу, но они не проверяют объекты приложения должным образом, поскольку повторяют некоторые (плохие) предположения.

Когда возникают сомнения, кажется, что мы должны действовать осторожно. И действуйте так, как будто мы нарушаем некоторые из правил тестирования, основанного на тестировании

Заметка. Мы на самом деле не нарушаем правила. Однако некоторые люди утверждают, что разработка через тестирование означает, что буквально каждое действие, которое вы предпринимаете, должно быть вызвано тестами. Включает ли это утренний кофе или перевод монитора в портретный режим? Очевидно, нет. Как насчет технических спайков?

Наша позиция такова.

  1. Установите шип рано и часто. 
  2. Если у вас есть основания полагать, что эта сумасшедшая вещь может сработать, вы можете формализовать всплеск с помощью тестов. И издеваться над объектами.
  3. Теперь вы можете написать остальную часть приложения, создав тесты и подгоняя код под эти тесты.

Часть импорта здесь не в том, чтобы создавать насмешки, пока вы действительно не поймете, что делаете.

Примеры книг

Теперь начинается сложная часть: написание книги.

Очевидно, что каждый пример должен иметь какой-то модульный тест. Я интенсивно использую doctest для этого. Каждый пример находится в тестовой строке doctest.

Код для главы может выглядеть следующим образом.

test_hello_world = '''
>>> print( 'hello world')
'hello world'
'''

__test__ = { n:v for n,v in vars().items() 
    if n.startswith('test_') }

if __name__ == '__main__':
    import doctest
    doctest.testmod()

Мы использовали функцию doctest, которая ищет словарь, назначенный переменной с именем __test__. Значения из этого словаря являются тестами, которые запускаются так, как если бы они были строками документов, найденными внутри модулей, функций или классов.

Это восхитительно просто. Пенять. Иллюстрировать. Скопируйте и вставьте пример в скрипт для целей тестирования и выставьте в тексте.

Пока мы не доберемся до внешних сервисов. И RESTful API-запросы и тому подобное. Это неловко издеваться. Главным образом потому, что смоделированный юнит-тест необычайно неинформативен.

Допустим, мы пишем о создании запроса RESTful API на  http://www.data.gov . Результаты запроса очень интересны. Механизм выполнения запроса является важным примером того, как работает REST API. И как  работают CKAN-сайты в целом.

Но если мы заменим urrlib.request на фиктивный urllib, модульный тест составит проверку, которую мы вызвали urlopen () с соответствующими параметрами. Важно для многих практических разработок программного обеспечения, но также и для людей, которые скачивают код, связанный с книгой.

Похоже, у меня есть четыре варианта:

  1. Улыбнись и перенеси это. Не все примеры должны быть чудесно детализированы.
  2. Придерживайтесь версии с шипами. Не издевайся Результаты могут отличаться, и некоторые тесты могут не работать на рабочем столе редактора.
  3. Пропустить тест
  4. Напишите несколько версий теста: версию «с реальным Интернетом» и версию «с корпоративными блокировками прокси-серверов на месте», которая использует макеты и работает везде.

До сих пор я активно использовал первые три. Четвертый неловко. Мы получаем такой код:

class Test_get_whois(unittest.TestCase):
    def test_should_get_subprocess(self):
        subprocess = MagicMock()
        subprocess.check_output.return_value=b'\nwords\n'
        with patch.dict('sys.modules', subprocess=subprocess):
            import subprocess
            from ch_2_ex_4 import get_whois
            result= get_whois('1.2.3.4')
        self.assertEquals( result, ['', 'words'] )
        subprocess.check_output.assert_called_with(['whois', '1.2.3.4'])

Это не много кода для целей разработки программного обеспечения предприятия. На самом деле, он немного слабоват, поскольку проверяет только счастливый путь.

Но для примера с книгой, кажется, много внимания уделяется макету модуля и освещению интересующей темы.

На самом деле, я не хочу никого выяснять, какова это объяснительная ценность, поскольку в нем всего 2 строки соответствующего кода, обернутые в 8 строк шаблона, необходимых для успешного макета модуля.

Я никак не недоволен модулем unitest.mock. Это отлично подходит для насмешливых модулей; Я думаю, что шаблон является приемлемым, принимая во внимание то, какое серьезное изменение мы вносим в среду выполнения тестируемого устройства.

Это не удается при экспликации.

Я размышляю над тем, как справиться с некоторыми из этих более сложных тестовых случаев. В прошлом я пропускал дела и использовал функцию многоточия doctest для работы с вариантами вывода. Я думаю, что я продолжу это делать, поскольку код мошенничества кажется менее полезным для читателей и слишком сосредоточен на чисто технической необходимости доказать, что весь код совершенно корректен.