Создание простого тестового задания средствами VBA Excel на конкретном примере. Загрузка вопросов и ответов с помощью массивов. Выставление оценки за тест.
Описание тестового задания
Простое тестовое задание состоит из пяти вопросов с пятью вариантами ответов на каждый. Оценивается пройденный тест от 0 до 5 баллов в зависимости от количества правильных ответов.
Пользователь выбирает на каждый вопрос один ответ из пяти предложенных и нажимает кнопку «Оценить». Результат выполнения тестового задания выводится в информационном окне MsgBox.
Форма и элементы управления
На пользовательской форме VBA Excel расположены пять элементов управления Frame (рамка) для размещения вопросов. В каждой рамке расположены по пять элементов OptionButton (переключатель) для размещения и выбора вариантов ответа.
Рамки нужны для объединения переключателей в группы, в которых только один элемент OptionButton из группы может иметь значение True. Это облегчает пользователю перевыбор ответа.
Кнопка CommandButton1 используется для запуска процедуры расчета оценки за пройденный тест.
Загрузка вопросов и ответов
Вопросы и варианты ответов присваиваются массивам непосредственно в коде VBA Excel. Из массивов информация передается на пользовательскую форму элементам управления Frame и OptionButton.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
Private Sub UserForm_Initialize() Dim arr1 As Variant, arr2 As Variant, i As Byte ‘Присваиваем список вопросов массиву arr1 arr1 = Array(“Сколько лапок у мухи?”, “На что меняют шило?”, _ “5! – это сколько?”, “Кто может стать мужем лосихи?”, _ “Что в списке цветов лишнее?”) ‘Присваиваем вопросы заголовкам рамок ‘из массива arr1 For i = 1 To 5 Controls(“Frame” & i).Caption = arr1(i – 1) Next ‘Присваиваем варианты ответов массиву arr2 arr2 = Array(“2”, “4”, “6”, “8”, “10”, “на вилы”, “на мыло”, _ “на силу”, “на рыло”, “на рынду”, “24”, “48”, “60”, “120”, _ “240”, “Вепрь”, “Упырь”, “Бугай”, “Мизгирь”, “Сохатый”, _ “Сенполия”, “Физалия”, “Циния”, “Пеларгония”, “Аквилегия”) ‘Присваиваем варианты ответов надписям ‘переключателей из массива arr2 For i = 1 To 25 Controls(“OptionButton” & i).Caption = arr2(i – 1) Next CommandButton1.Caption = “Оценка” Me.Caption = “Тестовое задание” End Sub |
Выставление оценки за тест
Для расчета оценки за пройденный тест используется свойство Value элемента управления OptionButton, которое равно True, если переключатель выбран. В тексте процедуры свойство Value не указано, так как оно является для OptionButton свойством по умолчанию.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
Private Sub CommandButton1_Click() Dim arr3 As Variant, n As Byte, i As Byte ‘Присваиваем порядковые номера правильных ‘ответов массиву arr3 arr3 = Array(“3”, “7”, “14”, “20”, “22”) ‘Считаем количество правильных ответов For i = 1 To 5 If Controls(“OptionButton” & arr3(i – 1)) Then n = n + 1 End If Next ‘Выводим результат в MsgBox MsgBox “Ваша оценка: “ & n End Sub |
Предложенное здесь простое тестовое задание в VBA Excel можно усовершенствовать, организовав загрузку вопросов и ответов в массивы с активного рабочего листа. Тогда на разных листах можно будет создать различные варианты тестов и запускать их одной программой, выбрав нужный лист.
Если ваши ученики освоили в Excel представление и
обработку данных, то можно переходить на
качественно новый уровень работы с Excel –
автоматизировать свою работу. Язык VBA (Visual Basic for
Application) – язык программирования, который
подходит для всех приложений Microsoft Office, это один
из самых простых в изучении и применении языков,
он является версией языка Visual Basic.
Предлагаю задания для создания проектов в виде
тестов в среде MS Excel и VBA.
Задание:
- Откройте Excel.
- Переименуйте Лист1 в Вопросник
и составьте таблицу.
Для каждого вопроса создайте пользовательские
формы и с помощью их заполните таблицу.
Пользовательские формы могут иметь вид:
UserForm1
UserForm2
- При вызове следующего вопроса закрывается
текущая форма, записываются результаты на лист Вопросник,
и открывается форма со следующим вопросом. - В форме с последним вопросом запрограммировано
только закрытие формы и запись результатов. - Спроектируйте на листе Excel Вопросник
кнопку вызова форм:
Примечание. Подумайте, как изменится
программа, если заполнить таблицу по вертикали.
Темы проектов:
1. Подобрать тест, обработать его, результаты
показать через пользовательскую форму.
2. Вопросник по любому предмету, результаты
которого обработать в Excel и выдать через
пользовательскую форму оценку:
3. Вопросник “МОЯ ВСЕЛЕННАЯ, ПОЗНАЙ СЕБЯ”
- Создать кнопку вызова.
- Создать форму Вопрос и ответы к ним:
Вопросы:
- Мое любимое занятие…
- Мой любимый цвет…
- Мое любимое животное…
- Мой лучший друг…
- Мой любимый звук…
- Мой любимый запах…
- Моя любимая игра…
- Моя любимая одежда…
- Моя любимая музыка…
- Мое любимое время года…
- Что я больше всего на свете люблю делать…
- Место, где я больше всего люблю бывать…
- Мой любимый певец или группа…
- Мои любимые герои…
- Я чувствую в себе способности к …
- Человек, которым я больше всего восхищаюсь …
- Лучше всего я умею …
- Я знаю, что смогу …
- Я уверен в себе потому, что …
Вопросник “Мне нравится”
- Мне нравится в школе то, что …
- Мне не нравится в школе то, что …
- Я просто в восторге от того, что …
- Мне не нравится на уроке то, что …
- Вот было бы здорово, если бы на уроке можно было
бы …
Смотри Приложение 1, где
можно определить тип темперамента.
Желаю удачи!!!
2 / 2 / 0 Регистрация: 01.11.2013 Сообщений: 56 |
|
1 |
|
08.12.2013, 19:41. Показов 17266. Ответов 32
Приветствую уважаемые форумчане! У меня курсовая работа по VBA, которую нужно сдать на предстоящей неделе, в связи с чем вынужден просить помощи, так как сам мягко говоря – ничего в этом не смыслю. (теорию выучил неплохо, написание кодов парализовано напрочь). 1. По кнопке вызывается титульная форма с приветствием (Небольшой рисунок, разные цвета, некоторый текст и кнопка “Начать тест”) Иными словами нечто похожее на онлайн тестирование. Я понимаю что прошу слишком много, но помимо представления должного вида работы, я не смыслю как это дело осуществить. Если есть нечто похожее, прошу – дайте ссылочку на тему или помогите разобраться с этим делом. Буду благодарен за самую простейшую работу, для примера, которую потом переделаю под себя. Заранее спасибо! Очень выручите
0 |
3217 / 966 / 223 Регистрация: 29.05.2010 Сообщений: 2,085 |
|
08.12.2013, 20:05 |
2 |
Уважаемый LaDav, для решения необходимы входные данные, ну так создайте, например в Excel, базу данных вопросов, возможных ответов, и определите бальность ответов. Но
(теорию выучил неплохо начни с чего нибудь, тогда может и помогут.
1 |
2 / 2 / 0 Регистрация: 01.11.2013 Сообщений: 56 |
|
08.12.2013, 20:42 [ТС] |
3 |
Уважаемый LaDav, для решения необходимы входные данные, ну так создайте, например в Excel, базу данных вопросов, возможных ответов, и определите бальность ответов. Но начни с чего нибудь, тогда может и помогут. Сейчас, я создал 2 формы и на листе введу необходимые данные. Минут 15, я быстро. Добавлено через 35 минут
Уважаемый LaDav, для решения необходимы входные данные, ну так создайте, например в Excel, базу данных вопросов, возможных ответов, и определите бальность ответов. Но начни с чего нибудь, тогда может и помогут. В общем вот. Все данные для ввода на листе Excel. В VBA 4 формы. (Приветствие, переход к началу теста, форма результата выводящаяся после всех вопросов и прощальная, с благодарностью за прохождение). В общем вариант ответа должен быть только 1, баллы в конце подсчитываться автоматически. Номер вопроса в форме выводится по мере ответа на вопросы (Вопрос № 1… Далее 1 меняется на 2 и т.д.) Очень прошу вас, если что то сможете сделать – я буду безмерно благодарен. Или хотя бы помогите с заготовкой, а я допишу (вставлю) оставшиеся варианты. Для кода у меня идей 0.
0 |
3217 / 966 / 223 Регистрация: 29.05.2010 Сообщений: 2,085 |
|
08.12.2013, 21:38 |
4 |
Примерно так:
1 |
2 / 2 / 0 Регистрация: 01.11.2013 Сообщений: 56 |
|
08.12.2013, 21:49 [ТС] |
5 |
Примерно так: Я даже не знаю как вас отблагодарить… Огромное спасибо. Я визуально подредактирую и это то, что мне в принципе нужно. Мои знания ограничились переходом между формами, за то по вашему примеру я почерпну для себя много нового. У меня крайне мало практики. Читать код в принципе могу и понимаю, что написано, а вот взять и самому настрочить – из головы вылетает, путаюсь и не могу собраться с мыслями. Еще раз спасибо! Прошу модераторов тему пока не закрывать, могут появиться вопросы, лучше тут сразу и спрошу.
0 |
2 / 2 / 0 Регистрация: 01.11.2013 Сообщений: 56 |
|
12.12.2013, 00:45 [ТС] |
6 |
Примерно так: Простите за беспокойство, это снова я. У меня возникла пара вопросов о работе, с которой вы мне помогли. Хочу снова обратиться к вам. 1. Можно ли сделать возврат на предыдущий вопрос? (добавив еще 1 кнопку по вторую форму) Я прикрепил файл с почти готовой работой, ее сдавать послезавтра, а к этим пунктам могут придраться. Если вас не затруднит, помоги еще разок, или хотя бы напишите код, которым можно воспользоваться. Заранее, большое спасибо!
0 |
3217 / 966 / 223 Регистрация: 29.05.2010 Сообщений: 2,085 |
|
12.12.2013, 17:27 |
7 |
А зачем возврат назад? Думал же человек когда отвечал. Думаю возврат не нужен, а вот ограничить переход можно.
1 |
2 / 2 / 0 Регистрация: 01.11.2013 Сообщений: 56 |
|
12.12.2013, 19:07 [ТС] |
8 |
А зачем возврат назад? Думал же человек когда отвечал. Думаю возврат не нужен, а вот ограничить переход можно. Еще раз огромное спасибо! А если меня все же попросят подправить и сделать переход назад, то какой для этого потребуется код? Создаю 3-ю кнопку перед “Продолжить”, так и назовем “Возврат” и что пропишем? Если конечно так можно, мне для себя было бы полезно! Чрезмерно благодарен!
0 |
3217 / 966 / 223 Регистрация: 29.05.2010 Сообщений: 2,085 |
|
12.12.2013, 19:23 |
9 |
А если меня все же попросят подправить и сделать переход назад, то какой для этого потребуется код? Думаю не попросят. Для решения необходимо много изменений, в т.ч. и хранение значений всех ответов, чтобы пересчитывать количество балов. Как вариант могу предложить создать кнопку “Начать сначала”, хотя Завершить и Запустить тест тоже самое.
1 |
2 / 2 / 0 Регистрация: 01.11.2013 Сообщений: 56 |
|
12.12.2013, 20:18 [ТС] |
10 |
Думаю не попросят. Для решения необходимо много изменений, в т.ч. и хранение значений всех ответов, чтобы пересчитывать количество балов. Как вариант могу предложить создать кнопку “Начать сначала”, хотя Завершить и Запустить тест тоже самое. Хорошо, еще раз спасибо! Надеюсь устроит такой вариант. Во всяком случае если попросят переделать, у меня будет больше времени и там уже постараюсь сам разобраться, воспользовавшись руководствами.
0 |
LaDav 2 / 2 / 0 Регистрация: 01.11.2013 Сообщений: 56 |
||||||||||||||||||
12.12.2013, 23:13 [ТС] |
11 |
|||||||||||||||||
Ребят, у меня еще такой вопрос (toiai ушел спать видимо, не могу у него спросить). Проблема в прочтении кода, мне нужно будет рассказать собственно как сделал работу, а я не все понимаю. Вы можете мне объяснить, что означают строки: 1.
Dim – переменная, Double – двойная, с плавающей точкой, а вот bal и nVopros что такое? Баллы и номер Вопроса? 2.
Не пойму что означают данные строки и для чего они прописаны 3.
Так же не пойму, что означает эта строка. Cells вроде указывает на диапазон, а что в скобках? 4.
Этот код так же вызывает затруднения. Пожалуйста, если кто может написать, что это значит, отпишитесь. Файлик с прописанными кодами прикрепил, на всякий случай. Вложения
0 |
2 / 2 / 0 Регистрация: 01.11.2013 Сообщений: 56 |
|
13.12.2013, 19:17 [ТС] |
12 |
Вопрос выше не актуален, я разобрался, но появились новые нюансы. Прошу пока не закрывать тему. Очень нужна будет ваша помощь, скорее всего завтра.
0 |
2 / 2 / 0 Регистрация: 01.11.2013 Сообщений: 56 |
|
15.12.2013, 20:15 [ТС] |
13 |
Думаю не попросят. Для решения необходимо много изменений, в т.ч. и хранение значений всех ответов, чтобы пересчитывать количество балов. Как вариант могу предложить создать кнопку “Начать сначала”, хотя Завершить и Запустить тест тоже самое. Здравствуйте! Я показал задание с которым вы мне помогли и преподавателю понравилось, но есть некоторые нюансы, в связи с чем вновь хотелось бы к вам обратиться (прошу прощения за назойливость). Меня попросили внести некоторые коррективы, которые я сам вряд ли смогу сделать. В общем меня попросили осуществить вот что: 1. Вопросы, количество баллов для них сделать на отдельном от кнопки листе и скрыть его (чтобы пользователь их не видел) Если я вам опять сделаю шапку с формами и примерным представлением того, как все должно быть, сможете помочь с кодами? Я надеюсь это последние замечания преподавателя и уже будет зачет по этому предмету, а после я постараюсь на каникулах разобраться с этим языком (по болезни пропускал много пар и ужасно усвоил практику).
0 |
2 / 2 / 0 Регистрация: 01.11.2013 Сообщений: 56 |
|
18.12.2013, 19:07 [ТС] |
14 |
Примерно так: Здравствуйте еще раз! Я накидал шапку к новым требованием для моего теста, нужна срочно ваша помощь, очень прошу помочь с кодом. На 1-м листе я оставил только кнопку. Я создал 5-ю форму, которую нужно вставить между после 1-й и перед 2-й, она должна служить для ввода данных (фамилии, имени, пола и даты прохождения теста), затем далее и переходим к самим вопросам из листа 2. После завершения вопросов, выводится на 3-й форме результат, который должен быть внесен вместе с информацией из 5-й формы на 3-й лист в соответствующие поля. Пожалуйста, если у вас есть время сегодня/завтра, помогите мне с этим решить. Навалилось перед сессией работы, не успеваю и не соображаю в данном предмете, но за каникулы надеюсь освою.
0 |
2 / 2 / 0 Регистрация: 01.11.2013 Сообщений: 56 |
|
19.12.2013, 11:17 [ТС] |
15 |
Ребята, кто может помочь с кодом, просмотрите пожалуйста темку! Очень срочно. Возможна оплата за вашу работу. Добавлено через 12 часов 52 минуты
0 |
6076 / 1320 / 195 Регистрация: 12.12.2012 Сообщений: 1,023 |
|
19.12.2013, 17:40 |
17 |
LaDav, пришлось попотеть, но получилось у меня вроде неплохо. Вариант, который выношу на ваше рассмотрение – в приложении. С уважением,
2 |
2 / 2 / 0 Регистрация: 01.11.2013 Сообщений: 56 |
|
19.12.2013, 18:04 [ТС] |
18 |
Времени совсем нет, занят, посмотри здесь Добавление данных через UserForm
LaDav, пришлось попотеть, но получилось у меня вроде неплохо. Огромное спасибо ребята, я честно не знаю, что бы без вас делал. У самого полнейший завал, просто не продохнуть, а программирование упустил на 1-м курсе из за болезни, пропустив практически весь семестр. Сейчас на каникулах буду разбираться и надеюсь у меня получится. Я готов вам заплатить за работу, правда только на qiwi кошелек, вы меня действительно очень выручили.
0 |
6076 / 1320 / 195 Регистрация: 12.12.2012 Сообщений: 1,023 |
|
19.12.2013, 22:08 |
19 |
LaDav, спасибо, но платить не надо – сделал эту работу не ради денег, а потому, что мне понравился ваш психологический тест. А вот ваше стремление посвятить часть каникул восполнению пробелов в познаниях VBA – это похвально! Желаю успехов в изучении языка, и может быть, вы даже расскажете нам что-нибудь интересное из того, что узнаете. С уважением,
0 |
2 / 2 / 0 Регистрация: 01.11.2013 Сообщений: 56 |
|
19.12.2013, 22:12 [ТС] |
20 |
Еще раз огромное вам спасибо! Я безусловно буду стараться!
0 |
Время на прочтение
7 мин
Количество просмотров 14K
Проблема
Есть определенная функциональная область приложения: некая экспертная система, анализирующая состояние данных, и выдающая результат — множество рекомендаций на базе набора правил. Компоненты системы покрыты определенным набором юнит-тестов, но основная «магия» заключается в выполнении правил. Набор правил определен заказчиком на стадии проекта, конфигурация выполнена.
Более того, поскольку после первоначальной приемки (это было долго и сложно — потому, что “вручную”) в правила экспертной системы регулярно вносятся изменения по требованию заказчика. При этом, очевидно, неплохо — бы проводить регрессионное тестирование системы, чтобы убедиться, что остальные правила все еще работают корректно и никаких побочных эффектов последние изменения не внесли.
Основная сложность заключается даже не в подготовке сценариев — они есть, а в их выполнении. При выполнении сценариев “вручную”, примерно 99% времени и усилий уходит на подготовку тестовых данных в приложении. Время исполнения правил экспертной системой и последующего анализа выдаваемого результата — незначительно по сравнению с подготовительной частью. Сложность выполнения тестов, как известно, серьезный негативный фактор, порождающий недоверие со стороны заказчика, и влияющий на развитие системы («Изменишь что-то, а потом тестировать еще прийдется… Ну его…»).
Очевидным техническим решением было бы превратить все сценарии в автоматизированные и запускать их регулярно в рамках тестирования релизов или по мере необходимости. Однако, будем ленивыми, и попробуем найти путь, при котором данные для тестовых сценариев готовятся достаточно просто (в идеале — заказчиком), а автоматические тесты — генерируются на их основе, тоже автоматически.
Под катом будет рассказано об одном подходе, реализующим данную идею — с использованием MS Excel, XML и XSLT преобразований.
Тест — это прежде всего данные
А где проще всего готовить данные, особенно неподготовленному пользователю? В таблицах. Значит, прежде всего — в MS Excel.
Я, лично, электронные таблицы очень не люблю. Но не как таковые (как правило — это эталон юзабилити), а за то, что они насаждают и культивируют в головах непрофессиональных пользователей концепцию «смешивания данных и представления» (и вот уже программисты должны выковыривать данные из бесконечных многоуровневых «простыней», где значение имеет все — и цвет ячейки и шрифт). Но в данном случае — мы о проблеме знаем, и постараемся ее устранить.
Итак, постановка задачи
- обеспечить подготовку данных в MS Excel. Формат должен быть разумным с точки зрения удобства подготовки данных, простым для дальнейшей обработки, доступным для передачи бизнес пользователям (последнее — это факультативно, для начала — сделаем инструмент для себя);
- принять подготовленные данные и преобразовать их в код теста.
Решение
Пара дополнительных вводных:
- Конкретный формат представления данных в Excel пока не ясен и, видимо, будет немного меняться в поисках оптимального представления;
- Код тестового скрипта может со временем меняться (отладка, исправление дефектов, оптимизация).
Оба пункта приводят к мысли, что исходные данные для теста необходимо предельно оделить и от формата, в котором будет осуществляться ввод, и от процесса обработки и превращения в код автотеста, поскольку обе стороны будут меняться.
Известная технология превращения данных в произвольное текстовое представление — шаблонизаторы, и XSLT преобразования, в частности — гибко, просто, удобно, расширяемо. В качестве дополнительного бонуса, использование преобразований открывает путь как к генерации самих тестов (не важно на каком языке программирования), так и к генерации тестовой документации.
Итак, архитектура решения:
- Преобразовать данные из Excel в XML определённого формата
- Преобразовать XML с помощью XSLT в финальный код тестового скрипта на произвольном языке программирования
Конкретная реализация на обеих этапах может быть специфична задаче. Но некоторые общие принципы, которые, как мне кажется, будут полезны в любом случае, приведены ниже:
Этап 1. Ведение данных в Excel
Здесь, честно говоря, я ограничился ведением данных в виде табличных блоков. Фрагмент файла — на картинке.
- Блок начинается со строки, содержащей название блока (ячейка “A5″). Оно будет использовано в качестве имени xml-элемента, так что содержание должно соответствовать требованиям. В той же строе может присутствовать необязательный “тип” (ячейка “B5″) — он будет использовано в качестве значения атрибута, так что тоже имеет ограничения.
- Каждая колонка таблицы содержит помимо “официального” названия, представляющего бизнес-термины (строка 8), еще два поля для “типа” (строка 6) и “технического названия” (строка 7). В процессе подготовки данных технические поля можно скрывать, но во время генерации кода использоваться будут именно они.
- Колонок в таблице может быть сколько угодно. Скрипт завершает обработку колонок как только встретит колонку с пустым значением “тип” (колонка D).
- Колонки со “типом”, начинающимся с нижнего подчеркивания — пропускаются.
- Таблица обрабатывается до тех пор, пока не встретиться строка с пустым значением в первой колонке (ячейка “A11”)
- Скрипт останавливается после 3 пустых строк.
Этап 2. Excel -> XML
Преобразование данных с листов Excel в XML — несложная задача. Преобразование производится с помощью кода на VBA. Тут могут быть варианты, но мне так показалось проще и быстрее всего.
Ниже приведу лишь несколько соображений — как сделать финальный инструмент удобнее в поддержке и использовании.
- Код представлен в виде Excel add-in (.xlam) — для упрощения поддержки кода, когда количество файлов с тестовыми данными более 1 и эти файлы создаются/поддерживаются более чем одним человеком. Кроме того — это соответствует подходу разделения кода и данных;
- XSLT шаблоны размещаются в одном каталоге с файлом add-in — для упрощения поддержки;
- Генерируемые файлы: промежуточный XML и результирующий файл с кодом, — желательно помещать в тот же каталог, что и файл Excel с исходными данными. Людям создающим тестовые скрипты будет удобнее и быстрее работать с результатами;
- Excel файл может содержать несколько листов с данными для тестов — они используются для организации вариативности данных для теста (например, если тестируется процесс, в котором необходимо проверить реакцию системы на каждом шаге): откопировал лист, поменял часть входных данных и ожидаемых результатов — готово. Все в одном файле;
- Поскольку все листы в рабочей книге Excel должны иметь уникальное имя — эту уникальность можно использовать в качестве части имени тестового скрипта. Такой подход дает гарантированную уникальность имен различных подсценариев в рамках сценария. А если включать в имя тестового скрипта название файла, то достичь уникальности названий скриптов становится еще проще — что особенно важно в случае если тестовые данные готовят несколько человек независимо. Кроме того, стандартный подход к именованию поможет в дальнейшем при анализе результатов теста — от результатов исполнения к исходным данным будет добраться очень просто;
- Данные из всех листов книги сохраняются в один XML файл. Для нас это показалось целесообразным в случае генерации тестовой документации, и некоторых случаях генерации тестовых сценариев;
- При генерации файла с данными для теста удобно оказалось иметь возможность не включать в генерацию отдельные листы с исходными данными (по разным причинам; например, данные для одного из пяти сценариев ещё не готовы — а тесты прогонять пора). Для этого мы используем соглашение: листы, где название начинается с символа нижнего подчёркивания — исключаются из генерации;
- В файле удобно держать лист с деталями сценария по которому создаются тестовые данные («Documentation») — туда можно копировать информацию от заказчика, вносить комментарии, держать базовые данные и константы, на которые ссылаются остальные листы с данными, и так далее. Разумеется, данный лист в генерации не участвует;
- Чтобы иметь возможность влиять на некоторые аспекты генерации финального кода тестовых скриптов, оказалось удобным включать в финальный XML дополнительную информацию «опции генерации», которые не являются тестовыми данными, но могут использоваться шаблоном для включения или исключения участков кода (по аналогии с pragma, define, итп.) Для этого мы используем именованные ячейки, размещённые на негенерируемом листе «Options»;
- Каждая строка тестовых данных должна иметь уникальный идентификатор на уровне XML — это здорово поможет при генерации кода и при обработке кросс-ссылок между строками тестовых данных, которые при этом необходимо формулировать в терминах как раз этих уникальных идентификаторов.
Фрагмент XML который получается из данных в Excel с картинки выше
<MasterRecord type="Type1">
<columns>
<column>
<type>Field</type>
<name>TechName1</name>
<caption>Business Name 1</caption>
</column>
<column>
<type>Field</type>
<name>TechName2</name>
<caption>Business Name 2</caption>
</column>
<column>
<type>Field</type>
<name>TechName3</name>
<caption>Business Name 3</caption>
</column>
</columns>
<row id="Type1_1">
<Field name="TechName1">A</Field>
<Field name="TechName2">123</Field>
<Field name="TechName3">2016-01-01</Field>
</row>
<row id="Type1_2">
<Field name="TechName1">B</Field>
<Field name="TechName2">456</Field>
<Field name="TechName3">2016-01-01</Field>
</row>
</MasterRecord>
Этап 3. XML -> Code
Эта часть предельно специфична задачам которые решаются, поэтому ограничусь общими замечаниями.
- Начальная итерация начинается по элементам, представляющим листы (различные тестовые сценарии). Здесь можно размещать блоки setup / teardown, утилит;
- Итерация по элементам данных внутри элемента сценария должна начинаться с элементов ожидаемых результатов. Так можно логично организовать сгенерированные тесты по принципу «один тест — одна проверка»;
- Желательно явно разделить на уровне шаблонов области, где генерируются данные, выполняется проверяемое действие, и контролируется полученный результат. Это возможно путём использования шаблонов с режимами (mode). Такая структура шаблона позволит в дальнейшем делать другие варианты генерации — просто импортируя этот шаблон и перекрывая в новом шаблоне необходимую область;
- Наряду с кодом, в тот же файл будет удобно включить справку по запуску тестов;
- Очень удобным является выделение кода генерации данных в отдельно вызываемый блок (процедуру) — так чтобы его можно было использовать как в рамках теста, так и независимо, для отладки или просто создания набора тестовых данных.
Финальный комментарий
Через какое-то время файлов с тестовыми данными станет много, а отладка и «полировка» шаблонов генерации тестовых скриптов будет все продолжаться. Поэтому, прийдется предусмотреть возможность «массовой» генерации автотестов из набора исходных Excel файлов.
Заключение
Используя описанный подход можно получить весьма гибкий инструмент для подготовки тестовых данных или полностью работоспособных автотестов.
В нашем проекте удалось довольно быстро создать набор тестовых сценариев для интеграционного тестирования сложной функциональной области — всего на данный момент около 60 файлов, генерируемых примерно в 180 тестовых классов tSQLt (фреймворк для тестирования логики на стороне MS SQL Server). В планах — использовать подход для расширения тестирования этой и других функциональных областей проекта.
Формат пользовательского ввода остается как и раньше, а генерация финальных автотестов можно менять по потребностям.
Код VBA для преобразования Excel файлов в XML и запуска преобразования (вместе с примером Excel и XML) можно взять на GitHub github.com/serhit/TestDataGenerator.
Преобразование XSLT не включено в репозиторий, поскольку оно генерит код для конкретной задачи — у вас все равно будет свой. Буду рад комментариям и pull request’ам.
Happy testing!
1. Overview
Welcome to the world of Excel VBA unit testing! In this tutorial, I am going to introduce you to Rubberduck VBA, and its unit testing capabilities.
What you’ll learn
- How to add test modules
- How to add unit tests
- How to run unit tests
- How to interpret test results
What you’ll need
- A Windows computer with Excel 2007, or newer
- Basic knowledge of Function and Sub procedures
All the commands that are listed below are executed on a Windows 10 machine with Excel 2016.
2. Get started
This step is only needed if you have not set up your development environment. You need to install Rubberduck VBA to your Excel. You can follow these instructions to install it.
Download Rubberduck installer from this link. Once download is finished, start the installer and follow the steps in the setup wizard.
Kicking off Excel
After setup has finished installing, it’s a good idea to launch Excel, open VBA Editor, and verify Rubberduck has been properly installed:
After installing the Rubberduck add-in, a new menu appears in VBA Editor.
The options we’ll use in this tutorial are located unter the Rubberduck
> Unit Tests
menu:
3. Create a function to test
In the previous step, we started Excel and opened Visual Basic Editor. In this step, you are going to insert a new code module, and add a new Function to it.
I’ve already prepared a function that we will unit test later, so just paste it into Module1:
Option Explicit | |
” | |
‘ Validate the password length so that it’s between 8-16 characters long | |
‘ | |
‘ Returns: | |
‘ | |
‘ TRUE – Password matches the lenght requirement | |
‘ FALSE – Password doesn’t match the length requirement | |
Function ValidatePasswordLength(password As String) As Boolean | |
Dim success As Boolean: success = False | |
‘ Validate the password is of correct length (between 8-16 characters) | |
Dim length As Long: length = Len(password) | |
If (length >= 8 And length <= 16) Then | |
success = True | |
End If | |
ValidatePasswordLength = success | |
End Function |
Here, you defined a new function, called ValidatePasswordLength(). It takes a single parameter of value string, and returns a boolean.
The purpose of the function is to assure that the password length is valid. It needs to be greater or equal to 8, and less or equal to 16 characters.
In next steps, we are going to create several unit tests that will test this function.
4. Insert a Test Module
Before you can start adding unit tests, you need to first insert a test module. A test module is a container for unit tests. Each test module can have zero or more unit tests. You can have any number of test modules in a project, depending on the complexity of your requirements. In this tutorial, you are just going to use a single Test Module.
To insert a new Test Module, you need to display the Test Explorer window. You do that with the Rubberduck
> Unit Tests
> Test Explorer
menu command:
Next, select the Test Explorer
> Add
> Test Module
command. This inserts a new Test Module called TestModule1:
Every time you insert a new test module, it contains these procedures: ModuleInitialize(), ModuleCleanup(), TestInitialize() and TestCleanup(). They are used to perform any initialization before running the tests, as well as cleaning up after tests have finished running.
Step 5: Add unit tests
If you try running the tests now, you won’t get any output. That’s because there are no unit test methods yet. So let’s start to add some tests. Usually it’s best to add the tests at the very bottom of this module, below ModuleInitialize(), ModuleCleanup(), TestInitialize() and TestCleanup() functions.
To insert a unit tests:
- First, make sure you’re located in TestModule1, just like in the previous screen shot.
- In Test Explorer, click
Add
>Test Method
.
Test Explorer inserts a new test method:
‘@TestMethod | |
Public Sub TestMethod1() ‘TODO Rename test | |
On Error GoTo TestFail | |
‘Arrange: | |
‘Act: | |
‘Assert: | |
Assert.Inconclusive | |
TestExit: | |
Exit Sub | |
TestFail: | |
Assert.Fail “Test raised an error: #” & Err.Number & ” – “ & Err.Description | |
End Sub |
What’s happening here?
Looking at the generated code, we see the Arrange, Act and Assert comments. These help guide us in writing better tests. For the purpose of this tutorial, we can delete all three of these comments.
Notice the @TestMethod attribute right in front of the function declaration? This attribute is automatically added to every test method. It’s there so that the method can get picked up by the test runner, as well as Test Explorer. Without it, test methods wouldn’t show up in Test Explorer.
To illustrate this concept, let’s click on the Refresh button in Test Explorer, and observe how the newly added test method now shows up in the Test Explorer window.
After refreshing, the test method shows up in Test Explorer
It’s a good idea to use the refresh button when you make changes to your methods, such as renaming them, deleting, or adding new ones.
Note: When you get more comfortable with writing unit tests, you can omit using the wizard — and code your test methods directly in the editor. You can do this by adding the @TestMethod attribute right in front of your test method.
Step 6: Customize the Unit Test
So far, this test method doesn’t do anything — it doesn’t test any code. So let’s customize it, by giving it a more appropriate name, and let’s add some code to it.
Let’s rename the test method from TestMethod1() to TestPasswordLenthIsTooSmall(), and delete the three “Arrange:”, “Act:” and “Assert:” comments.
Next, let’s modify the TestPasswordLenthIsTooSmall() test method, by having it invoke the ValidatePasswordLength() function we created in Step 3, by passing it the parameter “bob”.
You can do this by replacing the line:
Assert.Inconclusive
with:
Assert.IsFalse (ValidatePasswordLength("bob"))
The purpose of the ValidatePasswordLength() function, is to verify whether the password is valid, by comparing it’s length. If it’s within the range of 8-16 characters, the password is valid, and the function will return true. If it’s outside of that range, it will return false. Because we’re passing the parameter “bob”, we’re expecting to see a false result. That’s why we use Assert.IsFalse().
When you’re done, your code should look like this:
Option Explicit | |
Option Private Module | |
‘@TestModule | |
‘@Folder(“Tests”) | |
Private Assert As Object | |
‘@ModuleInitialize | |
Public Sub ModuleInitialize() | |
‘this method runs once per module. | |
Set Assert = CreateObject(“Rubberduck.AssertClass”) | |
End Sub | |
‘@ModuleCleanup | |
Public Sub ModuleCleanup() | |
‘this method runs once per module. | |
End Sub | |
‘@TestInitialize | |
Public Sub TestInitialize() | |
‘this method runs before every test in the module. | |
End Sub | |
‘@TestCleanup | |
Public Sub TestCleanup() | |
‘this method runs after every test in the module. | |
End Sub | |
‘@TestMethod | |
Public Sub TestPasswordLengthIsTooSmall() | |
On Error GoTo TestFail | |
Assert.IsFalse (ValidatePasswordLength(“bob”)) | |
TestExit: | |
Exit Sub | |
TestFail: | |
Assert.Fail “Test raised an error: #” & Err.Number & ” – “ & Err.Description | |
End Sub |
Assert.IsTrue and Assert.IsFalse above are methods from Rubberduck’s Assert class. Conveniently, it also provides a few other methods that we can use:
The Assert class in Rubberduck VBA provides some of the most commonly used assertions.
Believe it or not, that’s it! We’re done with creating our first test case.
Step 7: Run the test
Now starts the real fun: let’s run it. In order to run the test:
- Inside Test Explorer, click
Run
>All Tests
.
In Test Explorer, we can see a few things:
- Test result: failed, passed, and not run tests
- The name of the test module
- Name of the test method
- How long it took to execute the test, in ms
After running the unit test, the Test Explorer updates with the latest result.
That’s it! As you can see, our unit test passes. If you’d like to add the remaining test cases, you may do so. When you’re finished adding them, you just need to refresh the Test Explorer, and re-run the tests. The Test Explorer will run all of them, and show you the summary of results for each.
Once all your tests pass, you’re good to go!
Step 8: Add more test cases (optional)
So far, we’ve added one single test method, and ran it to make sure it passed.
We can use many different values to ValidatePasswordLength()‘s parameters. For example:
- “bob” –> should return FALSE
- “ASecretPassword” –> should return TRUE
- “” –> should return FALSE
- “123456” –> should return FALSE
- “IAmAVeryLongLongLongLongPassword#!{}$#.” –> should return FALSE
If we imagine running ValidatePasswordLength() with the inputs above, we should get results as indicated in the bullet points above.
Just for fun, I’ve added a few of the test cases above, and this is what I get after refreshing and running the tests:
Running multiple tests using Test Explorer
All the tests pass. Pretty neat!
Summary
In this tutorial, I’ve shown you how to get started with Rubberduck VBA to create and run your very first unit test. Congratulate yourself on your success!
Obviously, a real-world scenario doesn’t include just one single test. There can be many unit tests organized in many test modules, depending on the complexity of your solution. The great thing about using Rubberduck VBA is that it provides a Test Explorer which allows you to navigate your test cases.
If your company is considering implementing unit tests, or require tailor-made solutions for complex scenarios, please don’t hesitate to get in touch.