41 72 6c
41 72 6c

Reputation: 1780

Why does casting the result from a controller in a unit test return null?

I am in the process of equipping my sources with unit tests, but I made a mistake here. What can I do at this point if the value is really "null"? Is that even possible?

I have tried to figure out how others solve it but with the following thread I don't quite get along. C# in my unit test i want to see if it is null or an empty string

--> If I use IsNullOrEmpty() like in the example above, how does that look like in my code snippet?

This is the affected area in my unit test:

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

The following error message appears:

Message: System.ArgumentNullException : Value cannot be null. Parameter name: source

Edit - This is what my environment looks like:

Here is the class with the DeviceDetails object which has all information in the body.

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);
}

Unit-Test

 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);
}

Upvotes: 0

Views: 1340

Answers (2)

Scott Hannen
Scott Hannen

Reputation: 29222

Your controller calls this method of IDeviceManager, which is not mocked:

var device = _deviceManager.GetDevice(id);

Not mocking that method is one cause for the exception. But if you fix it and mock that method (using Setup to specify a result on the mock) you'll still get the same exception. More on that later. First, here's the path your code is going down:

Because it's not mocked, the return value from calling GetDevice on the mock will be null, so this happens:

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

The result of the method is a NotFound result.

Then, this is happening in the unit test:

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

result is a NotFoundResult. result as IEnumerable<DeviceDetails> returns null.

So you're effectively doing this:

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

The source parameter passed to the Single method is null, hence the exception.


If you mock GetDevice, you'll still get the same error for almost exactly the same reason. Now your code will return an OkObjectResult instead of a NotFoundResult. You'll try to cast that as IEnumerable<DeviceDetails>, it will still be null, and you'll get the same exception.

What you need is to get the value from the OkObjectResult, like this:

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

Upvotes: 3

Gauravsa
Gauravsa

Reputation: 6524

On the basis of code posted, it appears deviceInfo can be null. You can you the following:

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

 // rest of the code

Upvotes: 0

Related Questions