О тестировании GUI-приложений. "Из жизни".
Вот каким наблюдением (и выводами из него) хотел поделиться.
Бывает вот какая ситуация - GUI-приложение "когда-то" падает.
ТОЧНЫЙ СЦЕНАРИЙ работы к сожалению бывает НЕИЗВЕСТЕН.
Простое "протыкивание" - НЕ ПОМОГАЕТ.
Есть лишь "отрывочные" и "косвенные" свидетельства падения. Типа "обрывков технических логов" или рассказов пользователя "я нажал сюда... потом куда-то.. потом туда... и оно упало".
В общем - ЯВНОЙ картины повторения ошибки - НЕТ.
Повторю - "есть лишь косвенные свидетельства".
Что делают некоторые разработчики в данной ситуации?
Повторю - "некоторые". Далеко НЕ ВСЕ. Но тех кто "это" делает - "достаточно много".
Так что они делают?
Они "некоторым волшебным образом" сразу "вспоминают", что "у них есть все исходники" и начинают смотреть на систему как на "белый ящик". И сразу пытаются написать "интегральные" или Unit-тесты.
Вообще говоря стремление к написанию "интегральных" и (ТЕМ БОЛЕЕ) Unit-тестов - это ПРАВИЛЬНО и ПОХВАЛЬНО. Всегда проще иметь ДЕТЕРМИНИРОВАННЫЙ тест, который приводит к ошибке.
Но! НЕ В ДАННОМ СЛУЧАЕ.
Что люди пытаются делать?
Они смотрят на наши "отрывочные сведения" и пытаются (перепрыгнув "через голову") представить - "а как же система ВНУТРИ доходит до жизни такой".
Они пытаются взять "куски логов" или других "отрывочных сведений" и на их основе СКОМБИНИРОВАТЬ сценарий поведения системы в терминах проектных классов.
При этом они зачастую пытаются "интерполировать" поведение системы и и попытаться "угадать" - что же такое "привело к ошибке".
Это ещё ничего...
Но! Тут есть ЕЩЁ один момент.
В своих "попытках угадать" разработчики очень часто доходят до того, что пытаются "собрать ошибочный сценарий" оперируя private или protected полями существующих форм и компонентов.
Также иногда разработчики доходят до того, что начинают САМИ создавать экземпляры ПРОЕКТНЫХ классов. В погоне за "восстановлением ошибочного сценария".
И зачастую разработчикам УДАЁТСЯ "скомбинировать НЕЧТО", что ОЧЕНЬ "похоже на ошибочный сценарий", но НА САМОМ ДЕЛЕ таковым не являющееся.
Тут вот что хочу сказать?
До тех пор пока вы "в погоне за ошибкой" комбинируете код не обращаясь к private или protected членам. Или не пытаетесь СОЗДАВАТЬ НОВЫЕ экземпляры классов, то "всё ещё ничего". Можно "пробовать скомбинировать".
Но! Если вы "поймали себя за руку" за подобным желанием - обратиться к private или protected членам или создать НОВЫЕ ЭКЗЕМПЛЯРЫ проектных классов, то это - "звоночек".
Скорее всего - "вы что-то делаете не так". Вы уже не "ловите ошибку", а пытаетесь получить "её синтетическое воспроизведение".
Вот тут - МОМЕНТ ОСТАНОВИТЬСЯ и передохнуть.
И задуматься вот о чём:
А КАК НА САМОМ деле ошибка может быть воспроизведена у пользователя?
Ведь с точки зрения пользователя приложение это - ЧЁРНЫЙ ЯЩИК.
Какие методы воздействия пользователь имеет в своём арсенале?
Что "принуждает приложение" к тем или иным действия и реакциям?
Попробую выделить:
1. Нажатие на кнопки клавиатуры.
2. Перемещение мыши и нажатие на её кнопки.
3. Приход сообщений по TCP/IP.
4. Файловые нотификации от операционной системы.
5. Сообщения от таймера.
6. Нажатия на "кнопки интерфейса" (чтобы уж совсем глубоко мышь не обрабатывать).
Вот вроде и всё.
С чего бы "я начал" в такой ситуации?
Я бы начал с АНАЛИЗА наших "обрывочных сведений" и с сопоставления их с указанными СОБЫТИЯМИ.
Получив картину того, что "этот код может вызываться таким событием, а этот - таким событием" - я бы попытался не оперировать ПРОЕКТНЫМИ СУЩНОСТЯМИ, а "скомбинировать ошибочный сценарий" из подобных ВНЕШНИХ воздействий на систему.
И "обычно" - ошибочный сценарий получается ИМЕННО из таких внешних воздействий.
А вот - ДАЛЕЕ, когда ошибочный сценарий ЗАФИКСИРОВАН - уже ТОГДА можно переходить к "интегральным" или Unit-тестам.
P.S. вот кстати ссылка - http://www.delphinotes.ru/2011/03/blog-post.html
Не НАПРЯМУЮ, но - "В ТЕМУ".
P.P.S. У меня есть "СВЕЖИЙ пример из жизни" прямо на эту тему, но я пока его не буду публиковать. Ибо - он - "недозрел".
Вот каким наблюдением (и выводами из него) хотел поделиться.
Бывает вот какая ситуация - GUI-приложение "когда-то" падает.
ТОЧНЫЙ СЦЕНАРИЙ работы к сожалению бывает НЕИЗВЕСТЕН.
Простое "протыкивание" - НЕ ПОМОГАЕТ.
Есть лишь "отрывочные" и "косвенные" свидетельства падения. Типа "обрывков технических логов" или рассказов пользователя "я нажал сюда... потом куда-то.. потом туда... и оно упало".
В общем - ЯВНОЙ картины повторения ошибки - НЕТ.
Повторю - "есть лишь косвенные свидетельства".
Что делают некоторые разработчики в данной ситуации?
Повторю - "некоторые". Далеко НЕ ВСЕ. Но тех кто "это" делает - "достаточно много".
Так что они делают?
Они "некоторым волшебным образом" сразу "вспоминают", что "у них есть все исходники" и начинают смотреть на систему как на "белый ящик". И сразу пытаются написать "интегральные" или Unit-тесты.
Вообще говоря стремление к написанию "интегральных" и (ТЕМ БОЛЕЕ) Unit-тестов - это ПРАВИЛЬНО и ПОХВАЛЬНО. Всегда проще иметь ДЕТЕРМИНИРОВАННЫЙ тест, который приводит к ошибке.
Но! НЕ В ДАННОМ СЛУЧАЕ.
Что люди пытаются делать?
Они смотрят на наши "отрывочные сведения" и пытаются (перепрыгнув "через голову") представить - "а как же система ВНУТРИ доходит до жизни такой".
Они пытаются взять "куски логов" или других "отрывочных сведений" и на их основе СКОМБИНИРОВАТЬ сценарий поведения системы в терминах проектных классов.
При этом они зачастую пытаются "интерполировать" поведение системы и и попытаться "угадать" - что же такое "привело к ошибке".
Это ещё ничего...
Но! Тут есть ЕЩЁ один момент.
В своих "попытках угадать" разработчики очень часто доходят до того, что пытаются "собрать ошибочный сценарий" оперируя private или protected полями существующих форм и компонентов.
Также иногда разработчики доходят до того, что начинают САМИ создавать экземпляры ПРОЕКТНЫХ классов. В погоне за "восстановлением ошибочного сценария".
И зачастую разработчикам УДАЁТСЯ "скомбинировать НЕЧТО", что ОЧЕНЬ "похоже на ошибочный сценарий", но НА САМОМ ДЕЛЕ таковым не являющееся.
Тут вот что хочу сказать?
До тех пор пока вы "в погоне за ошибкой" комбинируете код не обращаясь к private или protected членам. Или не пытаетесь СОЗДАВАТЬ НОВЫЕ экземпляры классов, то "всё ещё ничего". Можно "пробовать скомбинировать".
Но! Если вы "поймали себя за руку" за подобным желанием - обратиться к private или protected членам или создать НОВЫЕ ЭКЗЕМПЛЯРЫ проектных классов, то это - "звоночек".
Скорее всего - "вы что-то делаете не так". Вы уже не "ловите ошибку", а пытаетесь получить "её синтетическое воспроизведение".
Вот тут - МОМЕНТ ОСТАНОВИТЬСЯ и передохнуть.
И задуматься вот о чём:
А КАК НА САМОМ деле ошибка может быть воспроизведена у пользователя?
Ведь с точки зрения пользователя приложение это - ЧЁРНЫЙ ЯЩИК.
Какие методы воздействия пользователь имеет в своём арсенале?
Что "принуждает приложение" к тем или иным действия и реакциям?
Попробую выделить:
1. Нажатие на кнопки клавиатуры.
2. Перемещение мыши и нажатие на её кнопки.
3. Приход сообщений по TCP/IP.
4. Файловые нотификации от операционной системы.
5. Сообщения от таймера.
6. Нажатия на "кнопки интерфейса" (чтобы уж совсем глубоко мышь не обрабатывать).
Вот вроде и всё.
С чего бы "я начал" в такой ситуации?
Я бы начал с АНАЛИЗА наших "обрывочных сведений" и с сопоставления их с указанными СОБЫТИЯМИ.
Получив картину того, что "этот код может вызываться таким событием, а этот - таким событием" - я бы попытался не оперировать ПРОЕКТНЫМИ СУЩНОСТЯМИ, а "скомбинировать ошибочный сценарий" из подобных ВНЕШНИХ воздействий на систему.
И "обычно" - ошибочный сценарий получается ИМЕННО из таких внешних воздействий.
А вот - ДАЛЕЕ, когда ошибочный сценарий ЗАФИКСИРОВАН - уже ТОГДА можно переходить к "интегральным" или Unit-тестам.
P.S. вот кстати ссылка - http://www.delphinotes.ru/2011/03/blog-post.html
Не НАПРЯМУЮ, но - "В ТЕМУ".
P.P.S. У меня есть "СВЕЖИЙ пример из жизни" прямо на эту тему, но я пока его не буду публиковать. Ибо - он - "недозрел".
Комментариев нет:
Отправить комментарий