nsubstitute/NSubstitute

Precompile error during Received assertion

InteXX opened this issue · 3 comments

I'm getting a precompile error while trying to assess whether my method under test was called:

Property access must assign to the property or use its value.

Screen Shot

According to the documentation, this should work:

oService.Received(1).IsElevated

So the whole thing is a real head-scratcher.

When alter it slightly and run the test, the boolean value always returns False:

Dim e = oService.Received(1).IsElevated

So I don't think that's the right way to do it.

Given this oddity—the apparent conflict between the documentation and the experience—how can I determine whether my method was called during my test run?

Here's my code:

'--------------------------------------------------
Public Interface IOsService
  ReadOnly Property IsElevated As Boolean
End Interface
'--------------------------------------------------
Public Class Os
  Public Sub New(Service As IOsService)
    Me.Service = Service
  End Sub

  Public Async Function CheckElevationAsync() As Task(Of Result(Of Boolean))
    Await Task.CompletedTask

    Return Me.Service.IsElevated.ToResult
  End Function

  Private ReadOnly Service As IOsService
End Class
'--------------------------------------------------
<Fact>
Public Async Function Is_Process_Elevated() As Task
  Dim oIsElevated As Result(Of Boolean)
  Dim oService As IOsService
  Dim oOs As Os

  ' Arrange
  oService = Substitute.For(Of IOsService)
  oService.IsElevated.Returns(True)
  oOs = New Os(oService)

  ' Act
  oIsElevated = Await oOs.CheckElevationAsync

  ' Assert
  oIsElevated.Value.Should.BeTrue()
  oService.Received(1).IsElevated ' <-- Error here
End Function
'--------------------------------------------------

I found the answer.

Received() works with functions and methods, not with properties.

--UPDATE--

'--------------------------------------------------
Public Interface IOsService
  ReadOnly Property IsElevated As Boolean
  Function GetIsElevated() As Boolean
End Interface
'--------------------------------------------------
Public Class Os
  Public Sub New(Service As IOsService)
    Me.Service = Service
  End Sub

  Public Async Function CheckElevationAsync() As Task(Of Result(Of Boolean))
    Await Task.CompletedTask

    Return Me.Service.GetIsElevated.ToResult
  End Function

  Private ReadOnly Service As IOsService
End Class
'--------------------------------------------------
<Fact>
Public Async Function Is_Process_Elevated() As Task
  Dim oIsElevated As Result(Of Boolean)
  Dim oService As IOsService
  Dim oOs As Os

  ' Arrange
  oService = Substitute.For(Of IOsService)
  oService.GetIsElevated.Returns(True)
  oOs = New Os(oService)

  ' Act
  oIsElevated = Await oOs.CheckElevationAsync

  ' Assert
  oIsElevated.Value.Should.BeTrue()
  oService.Received(1).GetIsElevated()
End Function
'--------------------------------------------------

Hi @InteXX ,
Thanks for updating the issue.

Properties can be asserted wit Received, but you do need to assign it somewhere or "use" it somehow. The assignment itself will be ignored. You could also write a method that explicitly ignores its argument.

Dim ignored = oService.Received(1).IsElevated
// or
ignoreValue(oService.Received(1).IsElevated)

Got it, thanks.

My problem was in the way I was thinking. For some reason I'd gotten myself fixated on the return value of IsElevated, when what we're really after with that line of code is determining whether the property was accessed. I was mixing apples and oranges.

It was a silly error, really.