使用Moq验证在单独的线程/线程池中发生的方法调用

时间:2019-03-27 09:51:06

标签: c# moq

我之前已经成功地使用Moq设置和验证了方法,但是以某种方式我无法使其正常工作。我没有遇到运气就对同一异常尝试了各种答案。

我已经实现了观察者模式,所以我在嘲笑IObserver<T>

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

OnCompleted()看起来像

public void OnCompleted()
{
}

现在在测试中,使用mock,我喜欢这样:

// 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(); 

我收到以下错误:

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.

编辑:SUT代码

SUT是使用工厂方法初始化的类。我将在这里总结相关部分:

有一个初始化方法:

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

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

CheckStatus方法检查在Initializer中启动的线程中的工作负载是否达到特定状态并引发指示完成的事件:

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()调用OnCompleted()方法:

private void NotifyObservers()
{
    foreach(o in observers)
    {
        o.OnCompleted();
    }
}

1 个答案:

答案 0 :(得分:3)

这可能是线程问题,或者在完成验证时可能尚未调用计时器。这意味着在调用Verify时尚未真正调用模拟成员。

在验证方法调用之前,您可能需要稍等片刻。

尝试在测试的“行为”和“断言”之间添加一个延迟,以使计时器有足够的时间来执行其操作。

//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();