2

I've a class that is initialised with a reference to a ITargetBlock<T> object. In my unit tests I wanted to check if the SendAsync<T> method of ITargetBlock<T> was called. So I used the following verification code:

   this.targetFake.Verify(mock => mock.SendAsync(It.IsAny<InternalMessage>()), Times.Never());

When calling this code I get the following exception:

System.NotSupportedException

HResult=0x80131515

Message=Invalid verify on a non-virtual (overridable in VB) member: mock => mock.SendAsync(It.IsAny())

Source=Moq

StackTrace:

at Moq.Mock.ThrowIfVerifyNonVirtual(Expression verify, MethodInfo method)

at Moq.Mock.Verify[T,TResult](Mock1 mock, Expression1 expression, Times times, String failMessage)

at Moq.Mock1.Verify[TResult](Expression1 expression, Times times)

After some research I found at that SendAsync is an extension method in ITargetBlock, which can't be mocked.

So I guess my unit test approach is not the correct one when working with TPL dataflow. Can anyone give me a hint how to test a class like:

 public class Detector
 {
     ...

     public Detector(ITargetBlock<FailureMessage> target, ITimer timer)
     {
         _target = target;
         _timer.Elapsed = TimerElapsed;
         ...
     }

     private async void TimerElapsed(object sender, ElapsedEventArgs e) 
     {
          bool errorCondition = false;

          // Perform checks that set errorCondition to true
          ...

          if (errorCondition)
          {
               var rv = await SendAsync(new FailureMessage());
               ...
          }

          ...
      }
 }

My idea was to inject an ITimer decorator. Using the ITimer interface allows me to simulate elapsed timers in unit test environments.

Thx

Moerwald
  • 10,448
  • 9
  • 43
  • 83
  • Try to find out what the extension method calls on the interface and setup the mock to expect that. That way when the extension method is called the code will still execute to completion. Do you have access to the source code of the extension method? – Nkosi Jan 16 '18 at 11:14
  • Found the source for the extension method https://github.com/dotnet/corefx/blob/master/src/System.Threading.Tasks.Dataflow/src/Base/DataflowBlock.cs#L299 – Nkosi Jan 16 '18 at 11:58
  • The more I look at the source the more I am reminded about coupling to code you have no control over, abstracted or not. Treat that data for dependency as a 3rd party dependency and encapsulate it behind abstractions you control and can manipulate for your own purposes. – Nkosi Jan 16 '18 at 12:43

0 Answers0