Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Verify a method call happening in a separate thread/thread pool using Moq

Tags:

c#

moq

I have successfully setup and verified methods with Moq before but somehow I can't get this to work. I tried various answers on the same exception without luck.

I have implemented observer pattern, so I'm mocking IObserver<T>:

var mock = new Mock<IObserver<T>>();
mock.Setup(s => s.OnCompleted());

Here the OnCompleted() looks something like

public void OnCompleted()
{
}

Now in the test, using the mock, I do like this:

// observable is the SUT.
var unsubscriber = observable.Subscribe(mock.Object);
// Cause OnCompleted() to be called: I verified that there's one observer in the observers list in observable and that my break point is correctly hit.

mock.Verify(v => v.OnCompleted(), Times.AtLeastOnce);
unsubscriber.Dispose(); 

I get the following error:

Message: Moq.MockException : 
Expected invocation on the mock at least once, but was never performed: v => v.OnCompleted()

Configured setups: 
IObserver<T> s => s.OnCompleted()
No invocations performed.

EDIT: SUT Code

SUT is a class initialized a using a factory method. I will summarize the relevant parts here:

There's an initializer method:

public void InitializeMyClass()
{
   for(var i = 0; i < threads.Count; i++)
   {
       Task.Factory.StartNew(() => Proc())
   }

   this.timer = new Timer(CheckStatus, null, 0, 1000);
}

CheckStatus method checks if the workloads in threads started in Initializer reaches a specific status and raises the event indicating completion:

private void CheckStatus(object status)
{
   // Inspect all background threads.
   // This is simply done by observing a set of values in a concurrent dict<int, bool>.:

   if (!this.concurrentDict.Values.Any(a => a))
   {
       this.NotifyObservers();
       this.timer.Change(Timeout.Infinite, Timeout.Infinite);
   }
}

NotifyObservers() calls the OnCompleted() method:

private void NotifyObservers()
{
    foreach(o in observers)
    {
        o.OnCompleted();
    }
}
like image 435
kovac Avatar asked Mar 05 '26 14:03

kovac


1 Answers

This could be a threading issue or the timer might not have invoked by the time the verification was done. Which means that the mock members were not actually called yet when Verify was invoked.

You might have to wait a bit before verifying method call.

Try adding a delay between the Act and Assertion in the test to give the timer enough time to do its thing.

//Arrange

//...

//Act
// observable is the SUT.
var unsubscriber = observable.Subscribe(mock.Object);
// Cause OnCompleted() to be called: I verified that there's one observer in the observers list in observable and that my break point is correctly hit.

await Task.Delay(TimeSpan.FromSeconds(1.5)); //Or some known duration

//Assert    
mock.Verify(v => v.OnCompleted(), Times.AtLeastOnce);
unsubscriber.Dispose(); 
like image 160
Nkosi Avatar answered Mar 08 '26 03:03

Nkosi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!