Я нахожусь в процессе оснащения своих источников модульными тестами, но здесь я сделал ошибку. Что я могу сделать в этот момент, если значение действительно «нулевое»? Это вообще возможно?
Я пытался выяснить, как другие решают эту проблему, но со следующей веткой я не совсем ладил. С# в моем модульном тесте я хочу увидеть, является ли он нулевым или пустой строкой
--> Если я использую 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);
}
Эта строка почти наверняка не вызывает исключения, если только deviceInfo.SerialNumber
не является плохо написанным свойством с get
, которое может генерировать исключения. Что еще есть в вашем методе тестирования?
Вы ищете это: Assert.IsNull(объект) ?
Пожалуйста, опубликуйте полный код с методом
Вы можете нажать и увидеть это? Ссылка на DeviceApi
Пожалуйста, разместите код в своем вопросе, а не в виде ссылки. Вы можете напрямую редактировать задать свой вопрос.
Assert.That(string.IsNullOrEmpty(deviceInfo.SerialNumber));
Для меня это выглядит как исключение, созданное вашим кодом где-то, а не как проблема с Assert. Есть ли в вашем коде метод с параметром source
?
Попробуйте добавить Assert.That(deviceInfo != null);
Вы издеваетесь над GetDevices
, но метод вызывает GetDevice
...
@HansKilian, нет параметра «источник»
var deviceInfos = result as IEnumerable<DeviceDetails>
почти наверняка производит deviceInfos
, то есть null
, потому что Ok(deviceDetails)
не будет IEnumerable
. Бросок метода — это Enumerable.Single
, который является методом расширения с первым параметром, названным (как вы уже догадались) source
. Если бы вы использовали приведение вместо as
, вы бы получили ошибку прямого преобразования.
Привет @JeroenMostert, спасибо за ваш ответ. Извините, что вынужден спрашивать вас еще раз, но я хочу понять, что именно я сделал не так. Почему здесь не должен работать IEnumerable? Если я изменю приведение следующим образом, будет ли var deviceInfos = result?.Value as IEnumerable<DeviceDetails>; быть действительным и работать здесь?
Нет, потому что Controller.Ok
просто оборачивает объект, который вы ему даете, в OkObjectResult
, а DeviceDetails
сам по себе не является перечислимым. То, что вы должны получить, это OkObjectResult
с Value
, это один DeviceDetails
, поэтому var deviceDetails = (DeviceDetails) ((OkObjectResult) result).Value
должно быть достаточно. (Нет реальной необходимости хеджировать свою ставку на значение null
или неправильный тип, поскольку код этого не создает, но вы можете добавить дополнительные утверждения для этого, если вы действительно хотите быть тщательным.) Я не уверен, что нет однако более чистый шаблон в MVC для этого.
Поскольку вы не издеваетесь над вызовом GetDevice
, я предполагаю, что макет возвращает null, когда вы его вызываете. Это приводит к ответу NotFound
. Поэтому, когда вы предполагаете, что получаете список устройств, все идет не так. Я думаю, что просмотр кода с помощью отладчика во время выполнения теста прояснит, что происходит.
Судя по опубликованному коду, 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();
Какая тестовая среда используется? Пожалуйста, добавьте полную трассировку стека и некоторый контекст. минимальный воспроизводимый пример было бы здорово.