Иногда при запуске многих тестов (например, когда тесты прогоняются по ночам без участия человека) часть тестов могут упасть с ошибками, которые затем не воспроизводятся при повторном запуске. Причины этого могут быть разными, однако обычно хочется заранее знать, воспроизведётся ли проблема, если перезапустить тест?
Один из способов получить ответ – сделать автоматический перезапуск упавших тестов после того, как все тесты выполнились. В этой статье мы рассмотрим, как это можно сделать.
Для начала определимся, как будет происходить процесс запуска:
- основной запуск Project Suite будет производиться из bat-файла.
- во время работы тестов будет обновляться ещё один bat-файл, в котором будет прописываться запуск каждого упавшего теста по отдельности.
- по окончании работы тестов, запущенных в первом bat-файле, проверяем, существует ли второй bat-файл. Если он существует, значит есть упавшие тесты и файл необходимо запустить.
Сначала напишем несколько тестов:
function test1()
{
Log.Message('Test 1');
}
function test2()
{
Log.Message('Test 2');
}
function test3()
{
Log.Error('Test 3');
}
function test4()
{
Log.Message('Test 4');
}
function test5()
{
Log.Error('Test 5');
}
Как видно из кода, у нас будет 3 теста без ошибок и 2 теста с ошибками. Все эти тесты нужно оформить в виде Test Items (правый клик на имени проекта, Edit | Test Items):

Теперь создадим обработчик ошибки OnLogError, который будет вызываться при каждом возникновении ошибки в тестах:
FAILED_TESTS_FILE = 'd:\\runFailedTests.bat';
TC_PATH = '"C:\\Program Files (x86)\\SmartBear\\TestComplete 10\\Bin\\TestComplete.exe"';
PJS_PATH = '"C:\\Users\\genka\\Documents\\TestComplete 10 Projects\\ProjectSuite1\\ProjectSuite1.pjs"';
TC_PARAMS = '/r /e /ns /SilentMode';
function GeneralEvents_OnLogError(Sender, LogParams)
{
if(!aqFileSystem.Exists(FAILED_TESTS_FILE))
{
aqFile.Create(FAILED_TESTS_FILE);
}
if(Project.TestItems.Current != undefined)
{
var projectName = aqFileSystem.GetFileNameWithoutExtension(Project.FileName);
var unitName = Project.TestItems.Current.ElementToBeRun.Caption.split('\\')[1].split(' - ')[0];
var routineName = Project.TestItems.Current.ElementToBeRun.Caption.split('\\')[1].split(' - ')[1];
var strToAdd = TC_PATH + ' ' + PJS_PATH + ' /project:' + projectName + ' /unit:' + unitName + ' /routine:' + routineName + ' ' + TC_PARAMS + '\n';
aqFile.WriteToTextFile(FAILED_TESTS_FILE, strToAdd, aqFile.ctANSI);
}
else
{
Log.Message('Skipping adding test to failed list, test item is undefined');
}
}
Сначала мы создаём bat-файл, если он ещё не создан (это произойдёт при первом срабатывании обработчика ошибок). Затем получаем имя проекта, модуля и функции, которые будут использоваться в командной строке для перезапуска тестов. Обратите внимание на условие:
if(Project.TestItems.Current != undefined)
Генерировать список упавших тестов нужно только при первом запуске. Когда мы запускаем тесты в первый раз, они запускаются с использованием Test Items, а значит свойство Project.TestItems.Current будет доступно, именно из него мы получаем затем имя модуля и функции. При повторном запуске мы передаём в командной строке имя функции, которую нужно запускать, а значит свойство Project.TestItems.Current будет undefined. В этом случае мы не обновляем bat-файл с упавшими тестами, а только кидаем в лог сообщение.
Теперь нам осталось создать первый bat-файл runAllTests.bat, с которого и начнётся работа тестов:
if exist D:\runFailedTests.bat (del D:\runFailedTests.bat) "C:\Program Files (x86)\SmartBear\TestComplete 10\Bin\TestComplete.exe" "C:\Users\genka\Documents\TestComplete 10 Projects\ProjectSuite1\ProjectSuite1.pjs" /r /e /ns /SilentMode if exist D:\runFailedTests.bat (D:\runFailedTests.bat)
Сначала мы удаляем старый файл с упавшими тестами, если он существует (он мог остаться с предыдущего запуска), затем выполняем основной Project Suite, после чего запускаем файл runFailedTests.bat, если он существует.
Если теперь запустить файл runAllTests.bat, то у нас сначала запустятся все 5 тестов, во время их работы сгенерируется файл runFailedTests.bat, который будет запущен по окончании работы первого тестов, когда закроется TestComplete.
И напоследок приведём текст сгенерированного файла runFailedTests.bat:
"C:\Program Files (x86)\SmartBear\TestComplete 10\Bin\TestComplete.exe" "C:\Users\genka\Documents\TestComplete 10 Projects\ProjectSuite1\ProjectSuite1.pjs" /project:TestRestartFailedTests /unit:Unit1 /routine:test3 /r /e /ns /SilentMode "C:\Program Files (x86)\SmartBear\TestComplete 10\Bin\TestComplete.exe" "C:\Users\genka\Documents\TestComplete 10 Projects\ProjectSuite1\ProjectSuite1.pjs" /project:TestRestartFailedTests /unit:Unit1 /routine:test5 /r /e /ns /SilentMode
На этом основная часть закончена, однако можно немного улучшить это решение несколькими мелочами:
- в блоке else обработчика ошибок можно генерировать ещё один список упавших тестов, которые отработали с ошибками при повторном запуске;
- путь к проекту в нашем случае захардкоджен в переменной PJS_PATH, однако в реальном проекте его нужно получать из свойства Project.FileName, так как проектов обычно несколько;
- пути к TestComplete.exe и к проекту в bat-файлах лучше оформить в виде переменных окружения, чтобы избавиться от длинных строк.