为什么从单元测试中的控制器强制转换结果返回null?

时间:2019-05-27 12:51:09

标签: c# asp.net unit-testing

我正在为源代码提供单元测试,但是我在这里犯了一个错误。 如果该值确实为“ null”,那我该怎么办? 那有可能吗?

我试图弄清楚其他人如何解决它,但是在下面的线程中,我不太了解。 C# in my unit test i want to see if it is null or an empty string

->如果像上面的示例中那样使用IsNullOrEmpty(),那么在我的代码段中是什么样子?

这是我的单元测试中的受影响区域:

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

出现以下错误消息:

消息:System.ArgumentNullException:值不能为null。参数名称:来源

编辑-这是我的环境:

这是带有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);
}

3 个答案:

答案 0 :(得分:3)

您的控制器调用了IDeviceManager的此方法,该方法没有被模拟

var device = _deviceManager.GetDevice(id);

不嘲笑该方法是导致异常的原因之一。但是,如果您对其进行修复并模拟该方法(使用Setup在模拟中指定结果),则仍然会遇到相同的异常。以后再说。首先,这是您的代码崩溃的路径:

由于未对它进行模拟,因此在模拟中调用GetDevice的返回值将为null,因此发生这种情况:

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

该方法的结果为NotFound结果。

然后,这在单元测试中发生:

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

resultNotFoundResultresult 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();

答案 1 :(得分:0)

根据发布的代码,似乎deviceInfo可以为null。您可以执行以下操作:

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

 // rest of the code

答案 2 :(得分:0)

当您具有null值时,应引发异常。

如果您已经这样做,则是另一行引发此错误。