Упражнение. Модульное тестирование функции Azure
Модульное тестирование является важной частью гибкой методики. Visual Studio предоставляет шаблон тестового проекта. Этот шаблон используется для создания модульных тестов для приложений, и ту же методику можно применить к тестированию для функций Azure.
В случае веб-сайта по продаже элитных часов у ваших разработчиков существует политика достижения по крайней мере 80 % покрытия кода в модульных тестах. Вы бы хотели реализовать ту же политику для функций Azure.
Здесь вы узнаете, как использовать платформу xUnit
тестирования с Visual Studio для тестирования Функции Azure.
Создание проекта модульного теста
Для начала нужно создать проект, содержащий модульные тесты, и добавить его к решению, которое содержит приложение-функцию Azure. Следуйте инструкциям ниже, чтобы создать проект модульного теста для тестирования функции WatchInfo.
В окне Обозревателя решений Visual Studio щелкните правой кнопкой мыши решение WatchPortalFunction, выберите Добавить, а затем — Создать проект.
В окне Добавить новый проект прокрутите вниз, выберите шаблон значка Тестовый проект xUnit C#+, а затем Далее.
Откроется окно Настройка нового проекта. В поле Имя проекта введите WatchFunctionsTests. Рядом с полем Расположение нажмите на значок обзора и выберите папку WatchPortalFunction.
Выберите Далее. Откроется окно Дополнительные сведения.
В разделе Требуемая версия .NET Framework. примите значение по умолчанию .NET 6.0 (долгосрочная поддержка).
Нажмите кнопку создания.
При добавлении проекта щелкните правой кнопкой мыши проект WatchFunctionTests в окне Обозреватель решений и выберите пункт "Управление пакетами NuGet".
В окне NuGet: WatchFunctionTests выберите вкладку "Обзор". В поле поиска введите Microsoft.AspNetCore.Mvc. Щелкните пакет Microsoft.AspNetCore.Mvc и выберите Установить.
Примечание.
Тестовый проект создаст макет среды HTTP. Классы, необходимые для этого, находятся в пакете Microsoft.AspNetCore.Mvc.
Подождите, пока установится пакет. Если появится сообщение Просмотр изменений, щелкните ОК. В диалоговом окне Принятие условий лицензионного соглашения нажмите Я принимаю.
После добавления пакета в окне Обозреватель решений в проекте WatchFunctionsTests щелкните правой кнопкой мыши файл UnitTest1.cs и нажмите кнопку "Переименовать". Измените имя файла на WatchFunctionUnitTests.cs. В появившемся диалоговом окне щелкните Да, чтобы переименовать все ссылки с UnitTest1 на WatchFunctionUnitTests.
В окне Обозревателя решений в проекте WatchFunctionsTest щелкните правой кнопкой мыши Зависимости и нажмите кнопку Добавить ссылку на проект.
В окне диспетчера ссылок выберите проект WatchPortalFunction и нажмите кнопку ОК.
Добавление модульных тестов для функции WatchInfo
Теперь можно добавить модульные тесты в тестовый проект. В сценарии элитных часов вы хотите убедиться, что функция WatchInfo всегда возвращает ответ ОК, если в строке запроса предоставляется модель, и ответ об ошибке, если строка запроса пуста или не содержит параметр model
.
Чтобы проверить это поведение, добавьте пару тестов фактов в WatchFunctionsTests.
В окне Обозреватель решений дважды щелкните файл WatchFunctionUnitTests.cs, чтобы открыть его в окне кода.
Добавьте в список в верхней части файла следующие директивы
using
.using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Internal; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Primitives; using Microsoft.Extensions.Logging.Abstractions;
Измените имя метода Test1 на TestWatchFunctionSuccess.
В теле метода TestWatchFunctionSuccess добавьте следующий код. Эта инструкция создает макет контекста HTTP и HTTP-запрос. Запрос включает строку запроса, которая содержит параметр
model
со значениемabc
.var queryStringValue = "abc"; var request = new DefaultHttpRequest(new DefaultHttpContext()) { Query = new QueryCollection ( new System.Collections.Generic.Dictionary<string, StringValues>() { { "model", queryStringValue } } ) };
Добавьте следующие операторы к методу. Эта инструкция создает фиктивное средство ведения журнала.
var logger = NullLoggerFactory.Instance.CreateLogger("Null Logger");
Добавьте в метод следующий код. Эти инструкции вызывают функцию WatchInfo, передавая фиктивный запрос и средство ведения журнала в качестве параметров.
var response = WatchPortalFunction.WatchInfo.Run(request, logger); response.Wait();
Добавьте в метод следующий код. Этот код проверяет правильность ответа функции. В этом случае функция должна возвращать ответ ОК, содержащий ожидаемые данные.
// Check that the response is an "OK" response Assert.IsAssignableFrom<OkObjectResult>(response.Result); // Check that the contents of the response are the expected contents var result = (OkObjectResult)response.Result; dynamic watchinfo = new { Manufacturer = "abc", CaseType = "Solid", Bezel = "Titanium", Dial = "Roman", CaseFinish = "Silver", Jewels = 15 }; string watchInfo = $"Watch Details: {watchinfo.Manufacturer}, {watchinfo.CaseType}, {watchinfo.Bezel}, {watchinfo.Dial}, {watchinfo.CaseFinish}, {watchinfo.Jewels}"; Assert.Equal(watchInfo, result.Value);
Готовый метод будет выглядеть, как показано ниже.
[Fact] public void TestWatchFunctionSuccess() { var queryStringValue = "abc"; var request = new DefaultHttpRequest(new DefaultHttpContext()) { Query = new QueryCollection ( new System.Collections.Generic.Dictionary<string, StringValues>() { { "model", queryStringValue } } ) }; var logger = NullLoggerFactory.Instance.CreateLogger("Null Logger"); var response = WatchPortalFunction.WatchInfo.Run(request, logger); response.Wait(); // Check that the response is an "OK" response Assert.IsAssignableFrom<OkObjectResult>(response.Result); // Check that the contents of the response are the expected contents var result = (OkObjectResult)response.Result; dynamic watchinfo = new { Manufacturer = "abc", CaseType = "Solid", Bezel = "Titanium", Dial = "Roman", CaseFinish = "Silver", Jewels = 15 }; string watchInfo = $"Watch Details: {watchinfo.Manufacturer}, {watchinfo.CaseType}, {watchinfo.Bezel}, {watchinfo.Dial}, {watchinfo.CaseFinish}, {watchinfo.Jewels}"; Assert.Equal(watchInfo, result.Value); }
Добавьте еще два метода с именем TestWatchFunctionFailureNoQueryString и TestWatchFunctionFailureNoModel. TestWatchFunctionFailureNoQueryString проверяет, что функция WatchInfo завершается корректно, если не получает строку запроса. TestWatchFunctionFailureNoModel проверяет тот же сбой, если функции передается строка запроса, которая не содержит параметр модели.
[Fact] public void TestWatchFunctionFailureNoQueryString() { var request = new DefaultHttpRequest(new DefaultHttpContext()); var logger = NullLoggerFactory.Instance.CreateLogger("Null Logger"); var response = WatchPortalFunction.WatchInfo.Run(request, logger); response.Wait(); // Check that the response is an "Bad" response Assert.IsAssignableFrom<BadRequestObjectResult>(response.Result); // Check that the contents of the response are the expected contents var result = (BadRequestObjectResult)response.Result; Assert.Equal("Please provide a watch model in the query string", result.Value); } [Fact] public void TestWatchFunctionFailureNoModel() { var queryStringValue = "abc"; var request = new DefaultHttpRequest(new DefaultHttpContext()) { Query = new QueryCollection ( new System.Collections.Generic.Dictionary<string, StringValues>() { { "not-model", queryStringValue } } ) }; var logger = NullLoggerFactory.Instance.CreateLogger("Null Logger"); var response = WatchPortalFunction.WatchInfo.Run(request, logger); response.Wait(); // Check that the response is an "Bad" response Assert.IsAssignableFrom<BadRequestObjectResult>(response.Result); // Check that the contents of the response are the expected contents var result = (BadRequestObjectResult)response.Result; Assert.Equal("Please provide a watch model in the query string", result.Value); }
Запуск тестов
В верхней строке меню в разделе Тест выберите Выполнить все тесты.
В окне обозревателя тестов все три теста должны завершиться успешно.
В окне обозревателя решений в проекте WatchPortalFunction дважды щелкните WatchInfo.cs, чтобы открыть файл в редакторе кода.
Найдите следующий код.
// Retrieve the model id from the query string string model = req.Query["model"];
Измените инструкцию, которая задает переменную
model
, следующим образом. Это изменение имитирует ошибку в коде, допущенную разработчиком.string model = req.Query["modelll"];
В верхней строке меню в разделе Тест выберите Выполнить все тесты. На этот раз тест TestWatchFunctionSuccess должен завершиться ошибкой. Эта ошибка возникает, так как функция WatchInfo не находит параметр, названный
modelll
в строке запроса, и поэтому функция возвращает неправильный ответ.
В этом уроке вы узнали, как создать проект модульного теста и реализовать модульные тесты для функции Azure.