Тестирование кода графического интерфейса: следует ли использовать фиктивную библиотеку?

Недавно я экспериментировал с TDD при разработке приложения с графическим интерфейсом на Python. Я нахожу очень обнадеживающим наличие тестов, которые проверяют функциональность моего кода, но было сложно следовать некоторым рекомендованным методам TDD. А именно, сначала было сложно написать тесты. И мне трудно сделать мои тесты читабельными (из-за широкого использования имитирующей библиотеки).

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

Во всяком случае, у меня есть много тестов, которые выглядят так:

def test_current_window_controller():
    def test(config):
        ac = AppController()
        m = Mocker()
        ac.iter_window_controllers = iwc = m.replace(ac.iter_window_controllers)
        expect(iwc()).result(iter(config))
        with m:
            result = ac.current_window_controller()
            assert result == (config[0] if config else None)
    yield test, []
    yield test, [0]
    yield test, [1, 0]

Обратите внимание, что на самом деле это три теста; все используют одну и ту же параметризованную функцию тестирования. Вот тестируемый код:

def current_window_controller(self):
    try:
        # iter_window_controllers() iterates in z-order starting
        # with the controller of the top-most window
        # assumption: the top-most window is the "current" one
        wc = self.iter_window_controllers().next()
    except StopIteration:
        return None
    return wc

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

Я обнаружил, что с помощью этого метода тестирования (и некоторой дисциплины) я могу легко написать код со 100% тестовым покрытием.

Мне интересно, являются ли эти тесты хорошими тестами? Сожалею ли я, что поступил так в будущем, когда наконец открою секрет написания хороших тестов?

Неужели я так сильно нарушаю основные принципы TDD, что мои тесты напрасны?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
6
0
1 244
3

Ответы 3

Модульные тесты действительно полезны при рефакторинге кода (т. Е. При полном переписывании или перемещении модуля). Если у вас есть модульные тесты до того, как вы внесете большие изменения, вы будете уверены, что не забыли переместить или добавить что-то, когда закончите.

Если вы пишете свои тесты после того, как написали свой код и заставили их пройти, вы не выполняете TDD. (при этом вы не получаете каких-либо преимуществ разработки Test-First или Test-Driven .. ознакомьтесь с вопросами SO, чтобы получить исчерпывающие книги по TDD)

One of the things I've noticed with using mocker is that it's easier to write the application code first and then go back and write the tests second, since most of the time I'm mocking many method calls and the syntax to write the mocked calls is much more verbose (thus harder to write) than the application code. It's easier to write the app code and then model the test code off of that.

Конечно, это проще, потому что вы просто проверяете, что небо оранжевое после того, как вы сделали его оранжевым, закрасив его специальной кистью. Это испытания дооснащения (для уверенности). Моки хороши, но вы должны знать, как и когда их использовать. Как говорится: «Когда у вас есть молоток, все выглядит как гвоздь». Также легко написать целую кучу нечитаемых и не столь полезных, как можно -быть испытаниями. Время, потраченное на понимание сути теста, - это потерянное время, которое можно использовать для исправления неисправных.

И дело в следующем:

  • Прочтите Моки - это не заглушки - Мартин Фаулер, если вы еще этого не сделали. Google опубликовал несколько задокументированных примеров хороших графических интерфейсов с шаблоном ModelViewPresenter (при необходимости поддельные / имитирующие пользовательские интерфейсы).
  • Изучите свои варианты и выбирайте с умом. Я сыграю парня с нимбом на левом плече в белом и скажу: «Не делай этого». Прочтите этот вопрос относительно мои причины - Святой Джастин у вас на правом плече. Думаю, ему тоже есть что сказать :)

Помните, что TDD - это не панацея. Это сложно, это должно быть сложно, и особенно сложно писать макет-тесты «заранее».

Поэтому я бы сказал - делайте то, что работает для вас. Даже это не "сертифицированный TDD". Я делаю в основном то же самое.

Возможно, вы захотите предоставить свой собственный API для графического интерфейса, который будет находиться между кодом контроллера и кодом библиотеки графического интерфейса. Это может быть проще имитировать, или вы даже можете добавить к нему несколько тестовых крючков.

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

Другие вопросы по теме