Упражнение. Исправление ошибок по результатам тестирования
На данном этапе вы можете выполнять модульные тесты по мере внесения изменений в рамках конвейера сборки. Кроме того, вы можете определять объем кода, проверенного с использованием тестов.
Прежде чем отправлять изменения в конвейер, всегда рекомендуется проводить локальное тестирование. Что произойдет, если кто-то забудет об этом и отправит изменение, которое нарушит работу всей сборки?
В этом уроке вы исправите сломанную сборку, вызванную неудачным модульным тестом. Вам предстоит сделать следующее:
- Получите начальный код из GitHub.
- Добавьте средства покрытия кода в проект.
- Отправить код в собственный репозиторий.
- Ознакомиться с результатами автоматического тестирования в конвейере и увидеть, что модульные тесты завершились неудачно.
- Воспроизвести ошибку локально.
- Проанализировать и исправить ошибку.
- Отправить исправление и убедиться в успешном выполнении сборки.
Проверка новых модульных тестов
Последняя функция команды включает в себя список лидеров. Нам нужно получить количество показателей из базы данных, чтобы можно было написать модульный тест для проверки IDocumentDBRepository<T>.GetItemsAsync
метода.
Этот тест будет выглядеть следующим образом. Добавлять код на данном этапе не нужно.
[TestCase(0, ExpectedResult=0)]
[TestCase(1, ExpectedResult=1)]
[TestCase(10, ExpectedResult=10)]
public int ReturnRequestedCount(int count)
{
const int PAGE = 0; // take the first page of results
// Fetch the scores.
Task<IEnumerable<Score>> scoresTask = _scoreRepository.GetItemsAsync(
score => true, // return all scores
score => 1, // we don't care about the order
PAGE,
count // fetch this number of results
);
IEnumerable<Score> scores = scoresTask.Result;
// Verify that we received the specified number of items.
return scores.Count();
}
Напомним, что встроенные данные, используемые для тестирования этого метода, предоставляются в тесте NUnit TestCase
. NUnit вызывает метод модульного теста ReturnRequestedCount
следующим образом:
ReturnRequestedCount(0);
ReturnRequestedCount(1);
ReturnRequestedCount(10);
Кроме того, в этом тесте используется свойство ExpectedResult
, которое позволяет упростить код теста и четко определить его предназначение. NUnit автоматически сравнивает возвращаемое значение со значением этого свойства, что избавляет от необходимости явно вызывать утверждение.
Мы выберем несколько значений, представляющих типичные запросы. Мы также будем включать 0, чтобы покрыть этот пограничный случай.
Извлечение ветви из GitHub
Как вы сделали ранее, извлеките failed-test
ветвь из GitHub и проверьте (или переключитесь на) эту ветвь.
В Visual Studio Code откройте интегрированный терминал.
Выполните следующие
git fetch
команды и команды, чтобы скачать ветвьfailed-test
из репозитория Майкрософт иgit checkout
переключиться на нее:git fetch upstream failed-test git checkout -B failed-test upstream/failed-test
Мы назвали ветвь
failed-test
для целей обучения. На практике вы назовете ветвь после ее назначения или функции.Выполните следующие команды, чтобы создать файл манифеста локального
ReportGenerator
инструмента, установить средство и добавитьcoverlet.msbuild
пакет в проект тестов:dotnet new tool-manifest dotnet tool install dotnet-reportgenerator-globaltool dotnet add Tailspin.SpaceGame.Web.Tests package coverlet.msbuild
Этот шаг необходим, так как ветвь
failed-test
не содержит действий, добавленных в ветвьunit-tests
.Добавьте файл тестового проекта и файл манифеста средства в промежуточный индекс и зафиксируйте изменения.
git add Tailspin.SpaceGame.Web.Tests/Tailspin.SpaceGame.Web.Tests.csproj git add .config/dotnet-tools.json git commit -m "Configure code coverage tests"
Выполните следующую
git push
команду, чтобы отправить ветвь в репозиторийfailed-test
GitHub:git push origin failed-test
Просмотр неудачно завершенного теста в конвейере
Предположим, что вы были в спешке и подтолкнули свою работу, не выполняя тесты один последний раз. К счастью, конвейер может помочь вам поймать проблемы рано, когда есть модульные тесты. Вы можете увидеть это здесь.
В Azure Pipelines трассировка сборки выполняется по конвейеру.
Разверните выполняемую задачу Выполнение модульных тестов — выпуск.
Обратите внимание, что метод теста
ReturnRequestedCount
завершился неудачно.Тест проходит, когда входное значение равно 0, но происходит сбой, если входное значение равно 1 или 10.
Сборка публикуется в конвейере только в случае успешного завершения предыдущей задачи. Здесь сборка не была опубликована из-за сбоя модульных тестов. Таким образом, исключается вероятность того, что кто-либо сможет использовать содержащую ошибки сборку.
На практике ручная трассировка сборки во время выполнения осуществляется не всегда. Ниже приведено несколько способов обнаружения сбоя.
Уведомление по электронной почте от Azure DevOps
Вы можете настроить Azure DevOps для отправки уведомления по электронной почте после завершения сборки. Если сборка завершилась неудачно, в строке темы этого сообщения будет указано "[Ошибка сборки]".
Azure Test Plans
В Azure DevOps выберите "Тестовые планы" и выберите "Запуски". Появится список недавно запущенных тестов, в том числе и последнего выполненного вами. Выберите последний выполненный тест. Вы видите, что два из восьми тестов завершилось ошибкой.
Панель мониторинга
В Azure DevOps выберите "Обзор" и выберите "Панели мониторинга". Обратите внимание, что в мини-приложении Тренд по результатам тестирования отображается ошибка. Мини-приложение Объем протестированного кода будет пустым, указывая на то, что тестирование не было завершено.
Значок сборки
Несмотря на то что в ветви
failed-test
значок сборки не включен в файл README.md, в случае неудачной сборки в GitHub будет показано следующее:
Анализ неудачно завершенного теста
При сбое модульных тестов обычно имеется два варианта в зависимости от характера сбоя:
- Если тест обнаруживает дефект в коде, исправьте код и повторно запустите тесты.
- Если функциональные возможности изменяются, измените тест на соответствие новым требованиям.
Локальное воспроизведение ошибки
В этом разделе вы будете воспроизводить сбой локально.
В Visual Studio Code откройте интегрированный терминал.
В терминале выполните следующую
dotnet build
команду, чтобы создать приложение:dotnet build --configuration Release
В терминале выполните следующую
dotnet test
команду, чтобы выполнить модульные тесты:dotnet test --no-build --configuration Release
В конвейере должны появиться те же ошибки, что и в конвейере. Ниже приведена часть выходных данных:
Starting test execution, please wait... A total of 1 test files matched the specified pattern. Failed ReturnRequestedCount(1) [33 ms] Error Message: Expected: 1 But was: 0 Stack Trace: at NUnit.Framework.Internal.Commands.TestMethodCommand.Execute(TestExecutionContext context) at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.<>c__DisplayClass1_0.<Execute>b__0() at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.RunTestMethodInThreadAbortSafeZone(TestExecutionContext context, Action action) Failed ReturnRequestedCount(10) [1 ms] Error Message: Expected: 10 But was: 9 Stack Trace: at NUnit.Framework.Internal.Commands.TestMethodCommand.Execute(TestExecutionContext context) at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.<>c__DisplayClass1_0.<Execute>b__0() at NUnit.Framework.Internal.Commands.BeforeAndAfterTestCommand.RunTestMethodInThreadAbortSafeZone(TestExecutionContext context, Action action) Failed! - Failed: 2, Passed: 6, Skipped: 0, Total: 8, Duration: 98 ms
Поиск причин ошибки
Обратите внимание, что каждый неудачный тест создает результат, отключаемый по одному. Например, вместо 10 тест возвращает 9.
Ознакомьтесь с исходным кодом для проверяемого LocalDocumentDBRepository<T>.GetItemsAsync
метода. Вы увидите следующее:
public Task<IEnumerable<T>> GetItemsAsync(
Func<T, bool> queryPredicate,
Func<T, int> orderDescendingPredicate,
int page = 1, int pageSize = 10
)
{
var result = _items
.Where(queryPredicate) // filter
.OrderByDescending(orderDescendingPredicate) // sort
.Skip(page * pageSize) // find page
.Take(pageSize - 1); // take items
return Task<IEnumerable<T>>.FromResult(result);
}
В этом сценарии можно проверить GitHub, чтобы узнать, был ли файл недавно изменен.
Вы подозреваете, что pageSize - 1
возвращается один меньший результат, и что это должно быть просто pageSize
. В нашем сценарии это ошибка, сделанная при отправке работы без тестирования, но в реальном сценарии вы можете проверить с разработчиком, который изменил файл на GitHub, чтобы определить причину изменения.
Совет
В GitHub также поддерживаются возможности для обсуждения и совместной работы. Вы можете оставить комментарии к запросу на вытягивание или открыть новый вопрос.
Исправление ошибки
В этом разделе вы исправите ошибку, изменив код обратно в исходное состояние и выполнив тесты для проверки исправления.
В Visual Studio Code откройте Tailspin.SpaceGame.Web/LocalDocumentDBRepository.cs из проводника.
Измените
GetItemsAsync
метод, как показано здесь:public Task<IEnumerable<T>> GetItemsAsync( Func<T, bool> queryPredicate, Func<T, int> orderDescendingPredicate, int page = 1, int pageSize = 10 ) { var result = _items .Where(queryPredicate) // filter .OrderByDescending(orderDescendingPredicate) // sort .Skip(page * pageSize) // find page .Take(pageSize); // take items return Task<IEnumerable<T>>.FromResult(result); }
В этой версии вместо
pageSize - 1
используетсяpageSize
.Сохраните файл.
В интегрированном терминале создайте приложение.
dotnet build --configuration Release
Вы увидите, что сборка выполнена успешно.
На практике вы можете запустить приложение и кратко попробовать его. В целях обучения мы пропустим это сейчас.
В терминале выполните модульные тесты.
dotnet test --no-build --configuration Release
Обратите внимание, что тесты завершаются успешно.
Starting test execution, please wait... A total of 1 test files matched the specified pattern. Passed! - Failed: 0, Passed: 8, Skipped: 0, Total: 8, Duration: 69 ms
В интегрированном терминале добавьте каждый измененный файл в индекс, зафиксируйте изменения и отправьте ветвь до GitHub.
git add . git commit -m "Return correct number of items" git push origin failed-test
Совет
Точка (
.
) в этомgit add
примере — подстановочный знак. Он соответствует всем файлам в текущем каталоге и его подкаталогах, для которых не было выполнено промежуточное сохранение.Прежде чем использовать этот подстановочный знак, рекомендуется выполняться
git status
перед фиксацией, чтобы убедиться, что вы выполняете промежуточные файлы, которые планируется выполнить.Вернитесь в Azure Pipelines. Просмотрите, как изменение распространяется по конвейеру. Тесты проходят, и общая сборка завершается успешно.
При необходимости, чтобы проверить результаты теста, можно выбрать вкладки "Тесты и покрытие кода" после завершения сборки.
Вы также можете ознакомиться с панелью мониторинга, чтобы просмотреть обновленную тенденцию результатов.
Отлично! Вы исправили сборку. Далее вы узнаете, как очистить среду Azure DevOps.