Почему приведение результата от контроллера в модульном тесте возвращает ноль?

Я нахожусь в процессе оснащения своих источников модульными тестами, но здесь я сделал ошибку. Что я могу сделать в этот момент, если значение действительно «нулевое»? Это вообще возможно?

Я пытался выяснить, как другие решают эту проблему, но со следующей веткой я не совсем ладил. С# в моем модульном тесте я хочу увидеть, является ли он нулевым или пустой строкой

--> Если я использую IsNullOrEmpty(), как в приведенном выше примере, как это будет выглядеть в моем фрагменте кода?

Это затронутая область в моем модульном тесте:

Assert.That(deviceInfo.SerialNumber == null);

Появляется следующее сообщение об ошибке:

Сообщение: System.ArgumentNullException: значение не может быть нулевым. Имя параметра: источник

Изменить. Вот как выглядит моя среда:

Вот класс с объектом DeviceDetails, который содержит всю информацию в теле.

public virtual IActionResult DevicesIdGet([FromRoute][Required]string id)
{
    var device = _deviceManager.GetDevice(id);

    if (device == null)
        return NotFound();

    var deviceDetails = new DeviceDetails
    {
        IsOnline = device.IsOnline(),
        SerialNumber = null
    };

    return Ok(deviceDetails);
}

Модульный тест

 private Device _testDevice;

 [SetUp]
 public void SetUp()
    {
        _testDevice = new Device
        {
            Id = 1,
            DeviceType = 1,
            DisplayName = "TestDevice",
            IpAddress = IPAddress.Parse("127.0.0.1"),
            IpAddressString = "127.0.0.1"
        };
    }

[Test]
public void If_DeviceIsAvailable_Then_DeviceIdIsSelected()
{
    // ARRANGE
    var deviceManagerMock = new Mock<IDeviceManager>();
    deviceManagerMock.Setup(manager => manager.GetDevices(false))
        .Returns(new List<Device>
                 {
                     _testDevice
                 })
        .Verifiable();

    var subject = new DevicesApiController(deviceManagerMock.Object);

    // ACT
    var result = subject.DevicesIdGet("1");

    // ASSERT
    var deviceInfos = result as IEnumerable<DeviceDetails>;
    var deviceInfo = deviceInfos.Single();
    Assert.That(deviceInfo.IsOnline == true);
    Assert.That(deviceInfo.SerialNumber == null);
}

Какая тестовая среда используется? Пожалуйста, добавьте полную трассировку стека и некоторый контекст. минимальный воспроизводимый пример было бы здорово.

Fildor 27.05.2019 14:56

Эта строка почти наверняка не вызывает исключения, если только deviceInfo.SerialNumber не является плохо написанным свойством с get, которое может генерировать исключения. Что еще есть в вашем методе тестирования?

Jeroen Mostert 27.05.2019 14:57

Вы ищете это: Assert.IsNull(объект) ?

Fildor 27.05.2019 14:58

Пожалуйста, опубликуйте полный код с методом

Gauravsa 27.05.2019 14:59

Вы можете нажать и увидеть это? Ссылка на DeviceApi

41 72 6c 27.05.2019 15:01

Пожалуйста, разместите код в своем вопросе, а не в виде ссылки. Вы можете напрямую редактировать задать свой вопрос.

Jeroen Mostert 27.05.2019 15:04
«Если я использую IsNullOrEmpty(), как в приведенном выше примере, как это будет выглядеть в моем фрагменте кода?» : Assert.That(string.IsNullOrEmpty(deviceInfo.SerialNumber));
Fildor 27.05.2019 15:04

Для меня это выглядит как исключение, созданное вашим кодом где-то, а не как проблема с Assert. Есть ли в вашем коде метод с параметром source?

Hans Kilian 27.05.2019 15:08

Попробуйте добавить Assert.That(deviceInfo != null);

Cleptus 27.05.2019 15:09

Вы издеваетесь над GetDevices, но метод вызывает GetDevice...

Hans Kilian 27.05.2019 15:12

@HansKilian, нет параметра «источник»

41 72 6c 27.05.2019 15:12
var deviceInfos = result as IEnumerable<DeviceDetails> почти наверняка производит deviceInfos, то есть null, потому что Ok(deviceDetails) не будет IEnumerable. Бросок метода — это Enumerable.Single, который является методом расширения с первым параметром, названным (как вы уже догадались) source. Если бы вы использовали приведение вместо as, вы бы получили ошибку прямого преобразования.
Jeroen Mostert 27.05.2019 15:13

Привет @JeroenMostert, спасибо за ваш ответ. Извините, что вынужден спрашивать вас еще раз, но я хочу понять, что именно я сделал не так. Почему здесь не должен работать IEnumerable? Если я изменю приведение следующим образом, будет ли var deviceInfos = result?.Value as IEnumerable<DeviceDetails>; быть действительным и работать здесь?

41 72 6c 27.05.2019 15:21

Нет, потому что Controller.Ok просто оборачивает объект, который вы ему даете, в OkObjectResult, а DeviceDetails сам по себе не является перечислимым. То, что вы должны получить, это OkObjectResult с Value, это один DeviceDetails, поэтому var deviceDetails = (DeviceDetails) ((OkObjectResult) result).Value должно быть достаточно. (Нет реальной необходимости хеджировать свою ставку на значение null или неправильный тип, поскольку код этого не создает, но вы можете добавить дополнительные утверждения для этого, если вы действительно хотите быть тщательным.) Я не уверен, что нет однако более чистый шаблон в MVC для этого.

Jeroen Mostert 27.05.2019 15:27

Поскольку вы не издеваетесь над вызовом GetDevice, я предполагаю, что макет возвращает null, когда вы его вызываете. Это приводит к ответу NotFound. Поэтому, когда вы предполагаете, что получаете список устройств, все идет не так. Я думаю, что просмотр кода с помощью отладчика во время выполнения теста прояснит, что происходит.

Hans Kilian 27.05.2019 15:33
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
15
757
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Судя по опубликованному коду, deviceInfo может быть нулевым. Вы можете следующее:

 if (deviceInfo == null)
      throw new ArgumentNullException(“source”);

 // rest of the code
Ответ принят как подходящий

Ваш контроллер вызывает этот метод IDeviceManager, который не издевается:

var device = _deviceManager.GetDevice(id);

Отсутствие насмешек над этим методом является одной из причин исключения. Но если вы исправите это и смоделируете этот метод (используя Setup, чтобы указать результат на макете), вы все равно получите то же исключение. Подробнее об этом позже. Во-первых, вот путь, по которому идет ваш код:

Поскольку это не мокап, возвращаемое значение от вызова GetDevice на макете будет нулевым, поэтому это происходит:

if (device == null)
    return NotFound();

Результатом метода является NotFound результат.

Затем это происходит в модульном тесте:

var deviceInfos = result as IEnumerable<DeviceDetails>;
var deviceInfo = deviceInfos.Single();

result есть NotFoundResult. result as IEnumerable<DeviceDetails> возвращается null.

Итак, вы эффективно делаете это:

IEnumerable<DeviceDetails> deviceInfos = null;
var deviceInfo = deviceInfos.Single();

Параметр source, переданный методу Single, имеет значение null, отсюда и исключение.


Если вы издеваетесь над GetDevice, вы все равно получите ту же ошибку почти по той же причине. Теперь ваш код будет возвращать OkObjectResult вместо NotFoundResult. Вы попытаетесь привести это как IEnumerable<DeviceDetails>, оно все равно будет null, и вы получите такое же исключение.

Что вам нужно, так это получить значение из OkObjectResult, например:

var actionResult = subject.DevicesIdGet("1") as OkObjectResult;
var deviceInfos = actionResult.Value as IEnumerable<DeviceDetails> ;
var deviceInfo = deviceInfos.Single();

Другие вопросы по теме