Ответ 1
Вы не можете тестировать модальные формы, вызывая ShowModal
; потому что, как вы совершенно правильно обнаружили, это приводит к тому, что ваш тестовый код "приостанавливается", в то время как модальная форма ожидает взаимодействия с пользователем.
Причиной этого является то, что ShowModal
переключает вас в "цикл вторичных сообщений", который не выходит до закрытия формы.
Однако модальные формы все еще могут быть протестированы.
- Покажите обычно модальную форму, используя метод обычный
Show
. - Это позволяет продолжить выполнение кода тестового кода и имитировать действия пользователя.
- Эти действия и эффекты можно протестировать как обычно.
- Вам понадобится дополнительный тест, весьма специфичный для модальных форм:
- Модальная форма обычно закрывается установкой модального результата.
- Тот факт, что вы использовали
Show
, означает, что форма не будет закрыта, установив модальный результат. - Что хорошо, потому что если вы теперь имитируете нажатие кнопки "Ok"...
- Вы можете просто проверить правильность
ModalResult
.
ПРЕДУПРЕЖДЕНИЕ
Вы можете использовать эту технику для проверки конкретной модальной формы, явно показывая ее немодально. Тем не менее, любой проверенный код, который показывает модальную форму (например, Диалог ошибок), приостанавливает ваш тестовый пример.
Даже ваш пример кода: Click ('OpenConfigButton');
приводит к вызову ShowModal и не может быть протестирован таким образом.
Чтобы решить эту проблему, вам нужно, чтобы ваши команды show были введены в ваше приложение. Если вы не знакомы с инъекцией зависимостей, я рекомендую видеоролики Misko Hevery Clean Code Talks, доступные на You Tube. Затем во время тестирования вы вводите подходящую версию ваших "команд шоу", которые не будут показывать модальную форму.
Например, ваша модальная форма может отображать диалоговое окно с ошибкой, если проверка не выполняется при нажатии кнопки Ok.
Итак:
1) Определите интерфейс (или абстрактный базовый класс) для отображения сообщений об ошибках.
IErrorMessage = interface
procedure ShowError(AMsg: String);
end;
2) Форма, которую вы тестируете, может содержать введенную ссылку на интерфейс (FErrorMessage: IErrorMessage
) и использовать ее для отображения ошибки всякий раз, когда проверка не выполняется.
procedure TForm1.OnOkClick;
begin
if (Edit1.Text = '') then
FErrorMessage.ShowError('Please fill in your name');
else
ModalResult := mrOk; //which would close the form if shown modally
end;
3) Стандартная версия IErrorMessage, используемая/введенная для производственного кода, просто отобразит сообщение как обычно.
4) Тестовый код будет вводить макет версии IErrorMessage, чтобы ваши тесты не были приостановлены.
5) Ваши тесты теперь могут выполнять случаи, которые обычно отображают сообщение об ошибке.
procedure TTestClass.TestValidationOfBlankEdit;
begin
Form1.Show; //non-modally
//Do not set a value for Edit1.Text;
Click('OkButton');
CheckEquals(0, Form1.ModalResult); //Note the form should NOT close if validation fails
end;
6) Вы можете сделать mock IErrorMessage еще дальше, чтобы действительно проверить текст сообщения.
TMockErrorMessage = class(TInterfaceObject, IErrorMessage)
private
FLastErrorMsg: String;
protected
procedure ShowError(AMsg: String); //Implementaion trivial
public
property LastErrorMsg: String read FLastErrorMsg;
end;
TTestClass = class(TGUITesting)
private
//NOTE!
//On the test class you keep a reference to the object type - NOT the interface type
//This is so you can access the LastErrorMsg property
FMockErrorMessage: TMockErrorMessage;
...
end;
procedure TTestClass.SetUp;
begin
FMockErrorMessage := TMockErrorMessage.Create;
//You need to ensure that reference counting doesn't result in the
//object being destroyed before you're done using it from the
//object reference you're holding.
//There are a few techniques: My preference is to explicitly _AddRef
//immediately after construction, and _Release when I would
//otherwise have destroyed the object.
end;
7) Теперь предыдущий тест будет выглядеть следующим образом:
procedure TTestClass.TestValidationOfBlankEdit;
begin
Form1.Show; //non-modally
//Do not set a value for Edit1.Text;
Click('OkButton');
CheckEquals(0, Form1.ModalResult); //Note the form should NOT close if validation fails
CheckEqulsString('Please fill in your name', FMockErrorMessage.LastErrorMsg);
end;