Note: An answer in either VB.NET or C# will be fine. I have no preference for this Q&A.
I'm trying to test my networking code and I'm running into a very strange problem: the GatewayAddresses
collection on my mocked NetworkInterface
always returns a Count
of 0
, even though its Enumerator
's internal list clearly contains an item:
I inserted this debugging code just before the assertions, and it works as expected:
Dim oEnumerator2 As IEnumerator(Of GatewayIPAddressInformation) = oGatewayAddresses.GetEnumerator
While oEnumerator2.MoveNext()
Dim oCurrentGatewayInfo As GatewayIPAddressInformation = oEnumerator2.Current
Me.Output.WriteLine($"Gateway IP Address: {oCurrentGatewayInfo.Address}")
End While
The string Gateway IP Address: 192.168.1.1
is written to the test results.
This assertion also succeeds:
Dim lMoved = oGatewayAddresses.GetEnumerator.MoveNext
oGatewayAddresses.GetEnumerator.Current.Address.Should.Be(oIPAddress)
But no matter what I try, the collection count always returns zero.
What could be the problem? My code is below.
--EDIT--
The problem lies either somewhere in my mocking setup or in NSubstitute itself. I prefer to consider the former.
Under this slight modification, the test passes:
'oNicService = Substitute.For(Of INicService)
oNicService = New NicService
' The actual function:
' Public Function GetActiveNetworkInterfaces() As IEnumerable(Of NetworkInterface) Implements INicService.GetActiveNetworkInterfaces
' Return NetworkInterface.GetAllNetworkInterfaces.Where(Function(Nic) Nic.OperationalStatus = OperationalStatus.Up)
' End Function
' Act
oActiveNics = oNicService.GetActiveNetworkInterfaces
oGatewayAddresses = oActiveNics.First.GetIPProperties.GatewayAddresses
' Assert
oGatewayAddresses.Should.NotBeNull()
oGatewayAddresses.Should.HaveCount(1) ' <-- This succeeds
How should I adjust my mocking setup in order to get this to work?
Service
Public Interface INicService
Function GetActiveNetworkInterfaces() As IEnumerable(Of NetworkInterface)
End Interface
Test
<Fact>
Public Sub GetActiveNetworkInterfaces_Should_Return_Correct_Gateway_Address()
' Arrange
Dim oMockGatewayAddresses As GatewayIPAddressInformationCollection
Dim oGatewayAddresses As GatewayIPAddressInformationCollection
Dim oMockGatewayInfo As GatewayIPAddressInformation
Dim oGatewayList As List(Of GatewayIPAddressInformation)
Dim oEnumerator As IEnumerator(Of GatewayIPAddressInformation)
Dim oActiveNics As IEnumerable(Of NetworkInterface)
Dim oNicService As INicService
Dim oIPAddress As IPAddress
Dim oMockNic1 As NetworkInterface
oMockGatewayAddresses = Substitute.For(Of GatewayIPAddressInformationCollection)
oMockGatewayInfo = Substitute.For(Of GatewayIPAddressInformation)
oIPAddress = IPAddress.Parse("192.168.1.1")
oMockNic1 = Substitute.For(Of NetworkInterface)
' Mock GatewayIPAddressInformation
oMockGatewayInfo.Address.Returns(oIPAddress)
oMockNic1.OperationalStatus.Returns(OperationalStatus.Up)
' Mock GatewayIPAddressInformationCollection
oGatewayList = New List(Of GatewayIPAddressInformation) From {oMockGatewayInfo}
' Create an enumerator that implements IEnumerator(Of GatewayIPAddressInformation)
oEnumerator = oGatewayList.GetEnumerator
' Configure the mock to return the enumerator
oMockGatewayAddresses.GetEnumerator.Returns(oEnumerator)
' Configure GetIPProperties.GatewayAddresses to return the mocked collection
oMockNic1.GetIPProperties.GatewayAddresses.Returns(oMockGatewayAddresses)
oNicService = Substitute.For(Of INicService)
oNicService.GetActiveNetworkInterfaces.Returns({oMockNic1})
' Act
oActiveNics = oNicService.GetActiveNetworkInterfaces
oGatewayAddresses = oActiveNics.First.GetIPProperties.GatewayAddresses
' Assert
oGatewayAddresses.Should.NotBeNull()
oGatewayAddresses.Should.HaveCount(1) ' <-- Fails here
oGatewayAddresses.First.Address.Should.Be(oIPAddress)
End Sub
ChatGPT to the rescue. (That thing's been getting me out of quite a few scrapes lately.)
OK, it turns out that I was mocking the wrong things and not mocking the right things.
Here's the updated test that passes:
<Fact>
Public Sub GetActiveNetworkInterfaces_Should_Return_Single_NetworkInterface_With_ExpectedGateway()
Dim oActiveNetworkInterfaces As IEnumerable(Of NetworkInterface)
Dim oExpectedGatewayAddress As IPAddress
Dim oGatewayCollection As GatewayIPAddressInformationCollection
Dim oGatewayAddresses As List(Of IPAddress)
Dim oIpProperties As IPInterfaceProperties
Dim oGatewayList As List(Of GatewayIPAddressInformation)
Dim oGatewayInfo As GatewayIPAddressInformation
Dim oNicService As INicService
Dim oNics As List(Of NetworkInterface)
Dim oNic As NetworkInterface
' Arrange
oGatewayCollection = Substitute.For(Of GatewayIPAddressInformationCollection)
oIpProperties = Substitute.For(Of IPInterfaceProperties)
oGatewayInfo = Substitute.For(Of GatewayIPAddressInformation)
oNicService = Substitute.For(Of INicService)
oNic = Substitute.For(Of NetworkInterface)
oNic.Name.Returns("Ethernet")
oNic.OperationalStatus.Returns(OperationalStatus.Up)
oExpectedGatewayAddress = IPAddress.Parse("192.168.1.254")
oGatewayInfo.Address.Returns(oExpectedGatewayAddress)
oGatewayList = New List(Of GatewayIPAddressInformation) From {oGatewayInfo}
oGatewayCollection.GetEnumerator.Returns(oGatewayList.GetEnumerator)
oGatewayCollection.Count.Returns(oGatewayList.Count)
oIpProperties.GatewayAddresses.Returns(oGatewayCollection)
oNic.GetIPProperties.Returns(oIpProperties)
oNics = New List(Of NetworkInterface) From {oNic}
oNicService.GetActiveNetworkInterfaces.Returns(oNics)
' Act
oActiveNetworkInterfaces = oNicService.GetActiveNetworkInterfaces
' Assert
oActiveNetworkInterfaces.Should.ContainSingle()
oGatewayAddresses = oActiveNetworkInterfaces.
Single.
GetIPProperties.
GatewayAddresses.
Select(Function(Gateway)
Return Gateway.Address
End Function).ToList
oGatewayAddresses.Should.ContainSingle()
oGatewayAddresses.Single.Should.Be(oExpectedGatewayAddress)
End Sub