public interface IFoo
{
int Bar(bool b);
}
var mock = new Mock<IFoo>();
mock.Setup(mc => mc.Bar(It.IsAny<bool>()))
.Callback<bool>(b => Console.WriteLine("Bar called with: " + b))
.Returns(42);
var ret = mock.Object.Bar(true);
Console.WriteLine("Result: " + ret);
// output:
// Bar called with: True
// Result: 42
public class SystemUnderTest
{
private readonly Repository _repository;
public SystemUnderTest(Repository repository)
{
_repository = repository;
}
public void Add(int a, int b)
{
int result = a + b;
_repository.StoreResult(result);
}
}
public class Repository
{
public void StoreResult(int result)
{
// stores the result in the database
}
}
using Moq;
using Xunit;
namespace TestLocal.Tests;
public class CallbackTest
{
private readonly SystemUnderTest _sut;
private readonly Mock<Repository> _repository;
public CallbackTest()
{
_repository = new Mock<Repository>(MockBehavior.Strict);
_sut = new SystemUnderTest(_repository.Object);
}
[Fact]
public void AddTest()
{
int a = 1;
int b = 2;
int result = -1;
_repository.Setup(x => x.StoreResult(3))
.Callback<int>(callbackResult => result = callbackResult)
.Verifiable();
_sut.Add(a,b);
Assert.Equal(a+b, result);
}
}
6条答案
按热度按时间yquaqz181#
难以击败https://github.com/Moq/moq4/wiki/Quickstart
如果这还不够清楚的话,我会称之为博士窃听器...
编辑:作为对您澄清的回应...
对于您执行的每个模拟方法
Setup
,您可以指示如下内容:.Callback
机制说“我现在不能描述它,但是当一个像这样的调用发生时,给我回电话,我会做需要做的事情”。作为同一个流畅调用链的一部分,你可以通过.Returns
控制返回的结果(如果有的话)。在QS示例中,一个例子是它们使返回的值每次都增加。通常,您不会经常需要这样的机制(xUnit测试模式中有类似测试中条件逻辑的反模式术语),如果有任何更简单或内置的方法来建立您所需要的,应该优先使用它。
Part 3 of 4 in Justin Etheredge's Moq series覆盖它,而there's another example of callbacks here
一个简单的回调示例可以在Using Callbacks with Moq post中找到。
i34xakig2#
下面是一个使用回调测试发送到处理插入的数据服务的实体的示例。
替代泛型方法语法:
然后你可以测试
4xy9mtcn3#
Callback
只是一种在调用mock的方法时执行任何自定义代码的方法。我最近遇到了一个有趣的用例。假设你期望一些对mock的调用,但是它们同时发生。所以你无法知道它们被调用的顺序,但是你想知道你期望的调用确实发生了(不考虑顺序)。你可以这样做:
顺便说一句,不要被误导性的“before
Returns
“和“afterReturns
“的区别所迷惑。这只是一个技术上的区别,即您的自定义代码是在Returns
求值之后还是之前运行。在调用者看来,两者都将在返回值之前运行。实际上,如果方法是void
-返回,你甚至不能调用Returns
,但它的工作原理是一样的。有关更多信息,请参见https://stackoverflow.com/a/28727099/67824。goucqfw64#
Moq中有两种
Callback
类型:一种发生在调用返回之前;另一个发生在调用返回之后。在这两个回调中,我们可以:
1.检查方法参数
1.撷取方法参数
1.更改上下文状态
jfewjypa5#
除了这里的其他好答案之外,我还使用它在抛出异常之前执行逻辑。(在某些测试案例中)需要掷回例外状况。在
Mock.Setup(...)
上呼叫.Throws(...)
会覆写Callback()
动作,而且永远不会呼叫它。不过,通过在回调中抛出一个异常,您仍然可以完成回调必须提供的所有好的功能,并且仍然抛出一个异常。hfyxw5xn6#
我再补充一个例子:
我需要测试的方法名为
Add
,它通过执行另一个方法将结果存储在数据库中,并返回void
。由于
Add
的返回类型,我不能直接得到结果并Assert它。我必须得到StoreResult
方法的输入。为此,我在模拟Repository
方法时使用回调。