Reputation: 1780
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
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
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