Я считаю, что в моих приложениях относительно мало возможностей для модульного тестирования. Большая часть кода, который я пишу, взаимодействует с данными таблиц или системой хранения, поэтому в принципе сложно провести модульное тестирование. Вначале я попробовал подход, который может быть похож на насмешку, когда я создал код с необязательным параметром. Если параметр был использован, то процедура будет использовать параметр вместо выборки данных из базы данных. Довольно просто настроить пользовательский тип, который имеет те же типы полей, что и строка данных, и передать его в функцию. Теперь у меня есть способ получить тестовые данные в процедуру, которую я хочу проверить. Внутри каждой процедуры был некоторый код, который заменял реальный источник данных на источник тестовых данных. Это позволило мне использовать модульное тестирование для более широкого спектра функций, используя мои собственные функции модульного тестирования. Написание юнит-теста легко, просто повторяющееся и скучное. В конце концов я отказался от юнит-тестов и начал использовать другой подход.
Я пишу собственные приложения в основном для себя, поэтому я могу позволить себе подождать, пока проблемы найдут меня, вместо того, чтобы иметь идеальный код. Если я пишу приложения для клиентов, как правило, клиент не полностью осознает, сколько стоит разработка программного обеспечения, поэтому мне нужен недорогой способ получения результатов. Написание модульных тестов - это все о написании теста, который помещает неверные данные в процедуру, чтобы посмотреть, сможет ли процедура обработать ее соответствующим образом. Модульные тесты также подтверждают, что хорошие данные обрабатываются надлежащим образом. Мой текущий подход основан на записи проверки ввода в каждую процедуру в приложении и поднятии флага успеха, когда код успешно завершен. Каждая вызывающая процедура проверяет наличие флага перед использованием результата. Если возникает проблема, она сообщается с помощью сообщения об ошибке. Каждая функция имеет флаг успеха, возвращаемое значение, сообщение об ошибке, комментарий и источник. Пользовательский тип (fr для возврата функции) содержит элементы данных. Любая данная функция может заполнять только некоторые элементы данных в пользовательском типе. Когда функция запускается, она обычно возвращает success = true и возвращаемое значение, а иногда и комментарий. Если функция завершается ошибкой, она возвращает success = false и сообщение об ошибке. Если происходит сбой цепочки функций, сообщения об ошибках меняются последовательно, но результат на самом деле гораздо более читабелен, чем обычная трассировка стека. Истоки также связаны, поэтому я знаю, где возникла проблема. Приложение редко дает сбой и точно сообщает о любых проблемах. Результат намного лучше, чем стандартная обработка ошибок.
Public Function GetOutputFolder(OutputFolder As eOutputFolder) As FunctRet
'///Returns a full path when provided with a target folder alias. e.g. 'temp' folder
Dim fr As FunctRet
Select Case OutputFolder
Case 1
fr.Rtn = "C:\Temp\"
fr.Success = True
Case 2
fr.Rtn = TrailingSlash(Application.CurrentProject.path)
fr.Success = True
Case 3
fr.EM = "Can't set custom paths – not yet implemented"
Case Else
fr.EM = "Unrecognised output destination requested"
End Select
exitproc:
GetOutputFolder = fr
End Function
Код объяснил.
eOutputFolder - это пользовательский Enum, как показано ниже
Public Enum eOutputFolder
eDefaultDirectory = 1
eAppPath = 2
eCustomPath = 3
End Enum
Я использую Enum для передачи параметров в функции, так как это создает ограниченный набор известных вариантов, которые может принять функция. Перечисления также обеспечивают intellisense при вводе параметров в функции. Я полагаю, они предоставляют элементарный интерфейс для функции.
'Type FunctRet is used as a generic means of reporting function returns
Public Type FunctRet
Success As Long 'Boolean flag for success, boolean not used to avoid nulls
Rtn As Variant 'Return Value
EM As String 'Error message
Cmt As String 'Comments
Origin As String 'Originating procedure/function
End Type
Пользовательский тип, такой как FunctRet, также обеспечивает завершение кода, что помогает. В рамках процедуры я обычно сохраняю внутренние результаты в анонимной внутренней переменной (fr), прежде чем присваивать результаты возвращаемой переменной (GetOutputFolder). Это делает процедуры переименования очень простыми, так как были изменены только верх и низ.
Итак, в заключение, я разработал структуру с ms-доступом, которая охватывает все операции, связанные с VBA. Тестирование постоянно записывается в процедуры, а не в единичное тестирование времени разработки. На практике код все еще выполняется очень быстро. Я очень тщательно оптимизирую функции нижнего уровня, которые можно вызывать десять тысяч раз в минуту. Кроме того, я могу использовать код в процессе разработки. Если возникает ошибка, она удобна для пользователя, и источник и причина ошибки обычно очевидны. Об ошибках сообщается из формы вызова, а не из какого-либо модуля на бизнес-уровне, который является важным принципом проектирования приложений. Кроме того, у меня нет бремени поддержки кода модульного тестирования, что действительно важно, когда я занимаюсь разработкой дизайна, а не программированием четко концептуализированного проекта.
Есть некоторые потенциальные проблемы. Тестирование не автоматизировано, и новый неверный код обнаруживается только при запуске приложения. Код не похож на стандартный код VBA (обычно он короче). Тем не менее, у подхода есть некоторые преимущества. Гораздо лучше использовать обработчик ошибок только для регистрации ошибки, так как пользователи обычно связываются со мной и дают мне значимое сообщение об ошибке. Он также может обрабатывать процедуры, которые работают с внешними данными. JavaScript напоминает мне VBA, мне интересно, почему JavaScript - это страна фреймворков, а VBA в ms-access - нет.
Через несколько дней после написания этого поста я обнаружил статью о CodeProject , которая приближается к тому, что я написал выше. В статье сравниваются и сравниваются обработка исключений и обработка ошибок. То, что я предложил выше, сродни обработке исключений.