最小起订量中的设置序列
Posted
技术标签:
【中文标题】最小起订量中的设置序列【英文标题】:SetupSequence in Moq 【发布时间】:2012-07-03 17:34:41 【问题描述】:我想要一个第一次返回0
的模拟,然后在此后调用该方法的任何时候返回1
。问题是如果方法被调用4次,我得写:
mock.SetupSequence(x => x.GetNumber())
.Returns(0)
.Returns(1)
.Returns(1)
.Returns(1);
否则,该方法返回null。
有什么办法可以写,在初始调用之后,方法返回1
?
【问题讨论】:
【参考方案1】:聚会有点晚了,但如果你还想使用 Moq 的 API,你可以在最后一次 Returns
调用的操作中调用 Setup
函数:
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...
我想演示使用 StepSequence
,但对于 OP 的特定情况,您可以简化并将所有内容放在 Setup
方法中:
mock.Setup(m => m.GetNumber())
.Returns(() =>
mock.Setup(m => m.GetNumber()).Returns(1);
return 4;
);
用 xunit@2.4.1 和 Moq@4.14.1 在这里测试了所有东西 - 通过 ✔
【讨论】:
这似乎不适用于“ReturnsAsync”。您不能在方法中使用 lamda 表达式作为参数。也许它适用于非异步开发,但现在谁在做呢? 问题不在于异步开发?【参考方案2】:只需设置一个扩展方法,例如:
public static T Denqueue<T>(this Queue<T> queue)
var item = queue.Dequeue();
queue.Enqueue(item);
return item;
然后像这样设置返回:
var queue = new Queue<int>(new []0, 1, 1, 1);
mock.Setup(m => m.GetNumber).Returns(queue.Denqueue);
【讨论】:
【参考方案3】:最干净的方法是创建一个Queue
并将.Dequeue
方法传递给Returns
.Returns(new Queue<int>(new[] 0, 1, 1, 1 ).Dequeue);
【讨论】:
@RomainVerdier - 不,它没有。我认为 OP 要求提供 4 次调用的解决方案。 All - 避免我最初的错误。如果您将其定义为具有 Returns(myQueue.Dequeue()) ,那么您只会得到第一个结果 - 因为您实际上已将结果出队,而不是提供 lambda 表达式。 @sfuqua - 这就是我的回答使用委托而不是调用的原因。 @JakubKonecki 是的,完全正确。我只是警告其他人要精确地遵循这种模式,不要像我那样意外地 Dequeue()。 @ben 我喜欢在测试结束时将我的异常抛出 Moq 语句(验证)放在 Assert 块(Arrange,Act,Assert)中,在那里您可以干净地检查是否调用了某些东西确切的次数【参考方案4】:您可以使用临时变量来跟踪方法被调用的次数。
例子:
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);
【讨论】:
【参考方案5】:这不是特别花哨,但我认为它会起作用:
var firstTime = true;
mock.Setup(x => x.GetNumber())
.Returns(()=>
if(!firstTime)
return 1;
firstTime = false;
return 0;
);
【讨论】:
我认为这不是线程安全的,所以如果您的测试涉及从不同线程调用GetNumber
的代码 - 您可能会多次返回 1
。为实现线程安全,Interlocked
类可用于firstTime
的读/写。
虽然对于给定的场景来说它是相当安全的,但在测试逻辑中使用 if
语句不应该太舒服。 解释:typemock.com/avoid-logic-inside-a-unit-test以上是关于最小起订量中的设置序列的主要内容,如果未能解决你的问题,请参考以下文章