Flo*_*ian 54 c# unit-testing moq mocking
我想模拟第一次返回0,然后在调用方法的任何时候返回1.问题是,如果方法被调用4次,我应该写:
mock.SetupSequence(x => x.GetNumber())
.Returns(0)
.Returns(1)
.Returns(1)
.Returns(1);
Run Code Online (Sandbox Code Playgroud)
否则该方法返回null.
有没有办法写下次在第一次调用该方法后,该方法返回1?谢谢
为SetupSequence设置更多"运营商"是否合适?如果您认为是,您可以投票:http: //moq.uservoice.com/forums/11304-general/suggestions/2973521-setupsequence-more-operators
Rom*_*ier 42
这不是特别的花哨,但我认为它会起作用:
var firstTime = true;
mock.Setup(x => x.GetNumber())
.Returns(()=>
{
if(!firstTime)
return 1;
firstTime = false;
return 0;
});
Run Code Online (Sandbox Code Playgroud)
Jak*_*cki 39
最干净的方法是创建一个Queue
和传递.Dequeue
方法Returns
.Returns(new Queue<int>(new[] { 0, 1, 1, 1 }).Dequeue);
小智 12
通常情况下,我不会费心为这样一个老问题提交新答案,但近年来这种情况ReturnsAsync
变得非常普遍,这使得潜在的答案变得更加复杂。
正如其他人所说,您基本上可以创建一个结果队列,并在您的Returns
调用中传递queue.Dequeue
委托,例如:
var queue = new Queue<int>(new[ ]{0,1,2,3});
mock.SetupSequence(m => m.Bar()).Returns(queue.Dequeue);
Run Code Online (Sandbox Code Playgroud)
但是,如果您要设置异步方法,我们通常应该调用ReturnsAsync
. queue.Dequeue
当传入时ReturnsAsync
将导致对正在设置的方法的第一次调用正常工作,但随后的调用会抛出NullReferenceException
. 您可以像其他一些示例一样创建自己的扩展方法来返回任务,但是这种方法不适用于SetupSequence
,并且必须使用Returns
来代替ReturnsAsync
。此外,必须创建一个扩展方法来处理返回结果,这违背了使用 Moq 的初衷。在任何情况下,任何返回类型为 Task 的方法(您已将委托传递给该方法)Returns
或ReturnsAsync
在通过 设置时在第二次调用时始终会失败SetupSequence
。
然而,这种方法有两种有趣的替代方法,只需要最少的额外代码。第一个选项是认识到模拟对象Setup
和SetupAsync
方法遵循 Fluent API 设计模式。这意味着,从技术上讲,Setup
、SetupAsync
、Returns
和ReturnsAsync
实际上都返回一个“Builder”对象。我所说的 Builder 类型对象是流利的 api 样式对象,例如QueryBuilder
、和/ 。这样做的实际结果是我们可以轻松地做到这一点:StringBuilder
ModelBuilder
IServiceCollection
IServiceProvider
var queue = new List<int>(){0,1,2,3};
var setup = mock.SetupSequence(m => m.BarAsync());
foreach(var item in queue)
{
setup.ReturnsAsync(item);
}
Run Code Online (Sandbox Code Playgroud)
这种方法允许我们同时使用SetupSequence
和ReturnsAsync
,在我看来,它遵循更直观的设计模式。
第二种方法是认识到Returns
能够接受返回 a 的委托Task
,并且Setup
总是返回相同的东西。这意味着如果我们要创建一个Queue<T>
像这样的扩展方法:
public static class EMs
{
public static async Task<T> DequeueAsync<T>(this Queue<T> queue)
{
return queue.Dequeue();
}
}
Run Code Online (Sandbox Code Playgroud)
那么我们可以简单地写:
var queue = new Queue<int>(new[] {0,1,2,3});
mock.Setup(m => m.BarAsync()).Returns(queue.DequeueAsync);
Run Code Online (Sandbox Code Playgroud)
或者可以使用AsyncQueue
from 的类Microsoft.VisualStudio.Threading
,这将允许我们这样做:
var queue = new AsyncQueue<int>(new[] {0,1,2,3});
mock.Setup(m => m.BarAsync()).Returns(queue.DequeueAsync);
Run Code Online (Sandbox Code Playgroud)
导致这一切的主要问题是,当到达设置序列末尾时,该方法被视为未设置。Setup
为了避免这种情况,如果在到达序列末尾后返回结果,您还应该调用标准。
我整理了一个关于此功能的相当全面的小提琴,其中包含您在做错事情时可能遇到的错误的示例,以及正确做事的几种不同方法的示例。
https://dotnetfiddle.net/KbJlxb
聚会有点晚了,但如果您仍想使用 Moq 的 API,您可以Setup
在最终Returns
调用的操作中调用该函数:
var mock = new Mock<IFoo>();
mock.SetupSequence(m => m.GetNumber())
.Returns(4)
.Returns(() =>
{
// Subsequent Setup or SetupSequence calls "overwrite" their predecessors:
// you'll get 1 from here on out.
mock.Setup(m => m.GetNumber()).Returns(1);
return 1;
});
var o = mock.Object;
Assert.Equal(4, o.GetNumber());
Assert.Equal(1, o.GetNumber());
Assert.Equal(1, o.GetNumber());
// etc...
Run Code Online (Sandbox Code Playgroud)
我想演示 using StepSequence
,但是对于 OP 的特定情况,您可以简化并在Setup
方法中包含所有内容:
mock.Setup(m => m.GetNumber())
.Returns(() =>
{
mock.Setup(m => m.GetNumber()).Returns(1);
return 4;
});
Run Code Online (Sandbox Code Playgroud)
用xunit@2.4.1和Moq@4.14.1在这里测试了所有东西- 通过了吗?
您可以使用临时变量来跟踪该方法被调用的次数。
例子:
public interface ITest
{ Int32 GetNumber(); }
static class Program
{
static void Main()
{
var a = new Mock<ITest>();
var f = 0;
a.Setup(x => x.GetNumber()).Returns(() => f++ == 0 ? 0 : 1);
Debug.Assert(a.Object.GetNumber() == 0);
for (var i = 0; i<100; i++)
Debug.Assert(a.Object.GetNumber() == 1);
}
}
Run Code Online (Sandbox Code Playgroud)
只需设置一个扩展方法,如:
public static T Denqueue<T>(this Queue<T> queue)
{
var item = queue.Dequeue();
queue.Enqueue(item);
return item;
}
Run Code Online (Sandbox Code Playgroud)
然后设置返回,如:
var queue = new Queue<int>(new []{0, 1, 1, 1});
mock.Setup(m => m.GetNumber).Returns(queue.Denqueue);
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
24309 次 |
最近记录: |