Вы не можете протестировать модальные формы, вызвав ShowModal
;потому что, как вы совершенно правильно обнаружили, это приводит к тому, что код вашего тестового примера «приостанавливается», в то время как модальная форма ожидает взаимодействия с пользователем.
Причина этого в том, что ShowModal
переключает вас во «вторичный цикл сообщений»это не завершится, пока форма не закроется.
Однако модальные формы все еще можно протестировать.
- Показать обычно модальную форму с использованием нормального
Show
метод. - Это позволяет продолжить выполнение кода тестового примера и имитировать действия пользователя.
- Эти действия и эффекты можно протестировать как обычно.
- Вам понадобится дополнительный тест, весьма специфичный для модальных форм:
- Модальная форма обычно закрывается установкой модального результата.
- Тот факт, что вы использовали
Show
означает формуне будет закрыто путем установки модального результата. - Что хорошо, потому что если вы теперь имитируете нажатие кнопки «ОК» ...
- Вы можете просто проверить, что
ModalResult
правильно.
ПРЕДУПРЕЖДЕНИЕ
Вы можете использовать эту технику для проверки конкретной модальной формы, явно показав ее немодально.Однако любой тестируемый код, который показывает модальную форму (например, Error Dialog), приостановит ваш тестовый пример.
Даже ваш пример кода: Click ('OpenConfigButton');
приводит к вызову ShowModal и не может быть протестирован таким образом.
Чтобы решить эту проблему, вам нужно, чтобы ваши «команды показа» были инъекционными в ваше приложение.Если вы не знакомы с внедрением зависимостей, я рекомендую видеоролики «Чистые разговоры по коду» Misko Hevery, доступные на 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) Вы можете сделать еще один шаг к ложному 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;