#c# #azure #unit-testing #fakeiteasy
Вопрос:
Я пытаюсь реализовать некоторые модульные/интеграционные тесты для HTTP-триггера Azure v3 и сталкиваюсь с некоторыми проблемами в процессе.
Ранее я написал несколько тестов для контроллера API, который использовал такой синтаксис:
TransactionResponse fakeResponse = new TransactionResponse { APIResponse = "Okay" };
var fakeSbus = A.Fake<IServiceBusPlatform>();
var fakeTransaction = A.Fake<ITransaction>();
A.CallTo(() => fakeTransaction.CreateTransaction(tran)).Returns(Task.FromResult(fakeResponse.APIResponse));
var controller = new SubmitController(fakeSbus, fakeTransaction);
var result = await controller._transaction.CreateTransaction(tran);
Assert.Equal(fakeResponse.APIResponse, result.ToString());
Это сработало нормально, потому что он просто тестировал dbcontext, а затем утверждал возврат.
Что я пытаюсь сделать с функцией Azure, так это оценить триггер на основе OkObjectResult, но внутри функции у меня есть несколько вызовов методов, а затем логика, зависящая от результата вызова метода. (возвращая список, используя свойство ListMember[0] для объявления var). Вот так:
var BatchResults = await _dbService.RetrieveBatch(session);
var CompanyID = BatchResults[0].CompanyID;
Обновление: Для большей ясности вот вся функция тестирования:
var fakeBatch = new List<RetrievedBatch>();
fakeBatch.Add(new RetrievedBatch
{
CompanyID = new Guid(),
});
var testResponse = new OkObjectResult("OKAY");
var request = A.Fake<HttpRequest>();
request.Method = "POST";
byte[] byteArray = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(fakeTransaction));
MemoryStream stream = new MemoryStream(byteArray);
request.Body = stream;
var logger = A.Fake<ILogger>();
var fakeService = A.Fake<IDbService>();
A.CallTo(() => fakeService.RetrieveBatch(fakeTransaction)).Returns(fakeBatch);
var test = fakeService.RetrieveBatch(fakeTransaction);
var SM = new SessionManager(fakeService);
var response = await SM.Run(request, logger);
О, и метод/тип внутри интерфейса выглядит так:
Task<List<RetrievedBatch>> RetrieveBatch(Transaction session);
Ошибка возникает внутри SM.Run(x,y). После небольшой отладки я вижу, что вызов A. возвращает правильные результаты внутри функции тестирования, но при запуске функции Azure значение не переносится, что является проблемой нарушения кода.
Любая помощь была бы признательна, так как я потратил слишком много времени, пытаясь разобраться в этом, и все приведенные примеры являются базовыми и, к сожалению, не очень полезными в этом сценарии.
Комментарии:
1. Покажите фактическую тестируемую функцию и полный тест, как он есть сейчас. Как вы уже поняли, показанные фрагменты слишком разрозненны, чтобы правильно оценить проблему. Скорее всего, вы неправильно настроили сопоставитель аргументов, из-за чего макет по умолчанию возвращает значение null.
2. Я обновил свой вопрос с помощью кода внутри моей функции, выполняющей модульный тест 🙂
Ответ №1:
Я думаю, что настоящая проблема fakeTransaction
в том, что внутри вызова находится не тот же объект SM.Run
, что и в тесте. Какой именно это класс? У нас нет определения fakeTransaction
выше, но я вижу, что вы отправляете в запрос его сериализованное представление, а не исходный объект.
Поэтому SM.Run
в конечном итоге вызывает fakeService.RetrieveBatch(Transaction session)
восстановленный session
объект. Какова семантика равенства Transaction
класса? Метод настроенной подделки RetrieveBatch
, как описано в разделе Ограничения аргументов, будет сравнивать свои входные данные с fakeTransaction
использованием object.Equals
, и если он не совпадает, ваше настроенное поведение не будет запущено.
Если вы не уверены в семантике равенства Transaction
, рассмотрите возможность восстановления транзакции из массива байтов прямо в тесте и запуска object.Equals
на двух объектах. Это покажет вам, сравниваются ли они как равные.
Если Transaction
окажется, что семантика равенства на основе значений отсутствует, вам, скорее всего, придется использовать один из других механизмов ограничения аргументов, таких как пользовательский сопоставитель, который проверяет свойства транзакции или, возможно, даже игнорирует использование фактического значения A<Transaction>.Ignored
.
Комментарии:
1. Вы были абсолютно правы, я добавил<Транзакцию>. Игнорируемый оператор в качестве параметра функции, затем при отладке я смог определить, что я ожидал увидеть.. Я не хотел тратить слишком много времени на создание пользовательского сопоставления, так как в этом случае я знаю, что буду передавать только объект с аналогичными свойствами, хотя, возможно, придется изучить это в будущем. Спасибо за быстрые ответы и советы, очень признателен!