目前我有:
[Test]
public void DrawDrawsAllScreensInTheReverseOrderOfTheStack() {
// Arrange.
var screenMockOne = new Mock<IScreen>();
var screenMockTwo = new Mock<IScreen>();
var screens = new List<IScreen>();
screens.Add(screenMockOne.Object);
screens.Add(screenMockTwo.Object);
var stackOfScreensMock = new Mock<IScreenStack>();
stackOfScreensMock.Setup(s => s.ToArray()).Returns(screens.ToArray());
var screenManager = new ScreenManager(stackOfScreensMock.Object);
// Act.
screenManager.Draw(new Mock<GameTime>().Object);
// Assert.
screenMockOne.Verify(smo => smo.Draw(It.IsAny<GameTime>()), Times.Once(),
"Draw was not called on screen mock one");
screenMockTwo.Verify(smo => smo.Draw(It.IsAny<GameTime>()), Times.Once(),
"Draw was not called on screen mock two");
}
但是我在生产代码中绘制对象的顺序无关紧要。我可以先做一个,或者两个没关系。但是它应该很重要,因为抽奖顺序很重要。
你如何(使用Moq)确保按特定顺序调用方法?
修改
我摆脱了那个考验。 draw方法已从我的单元测试中删除。我只需要手动测试它的工作原理。顺序的颠倒虽然被带入了一个单独的测试类,在那里进行了测试,所以并非一切都不好。
感谢您关注他们正在研究的功能的链接。我当然希望它能很快得到补充,非常方便。
答案 0 :(得分:31)
我最近创建了Moq.Sequences,它可以检查Moq中的排序。您可能需要阅读描述以下内容的post:
典型用法如下:
[Test]
public void Should_show_each_post_with_most_recent_first_using_sequences()
{
var olderPost = new Post { DateTime = new DateTime(2010, 1, 1) };
var newerPost = new Post { DateTime = new DateTime(2010, 1, 2) };
var posts = new List<Post> { newerPost, olderPost };
var mockView = new Mock<BlogView>();
using (Sequence.Create())
{
mockView.Setup(v => v.ShowPost(newerPost)).InSequence();
mockView.Setup(v => v.ShowPost(olderPost)).InSequence();
new BlogPresenter(mockView.Object).Show(posts);
}
}
答案 1 :(得分:13)
使用Moq CallBacks的简单解决方案:
[TestMethod]
public void CallInOrder()
{
// Arrange
string callOrder = "";
var service = new Mock<MyService>();
service.Setup(p=>p.FirstCall()).Returns(0).CallBack(()=>callOrder += "1");
service.Setup(p=>p.SecondCall()).Returns(0).CallBack(()=>callOrder += "2");
var sut = new Client(service);
// Act
sut.DoStuff();
// Assert
Assert.AreEqual("12", callOrder);
}
答案 2 :(得分:4)
它似乎目前尚未实施。见Issue 24: MockSequence。 This thread讨论了这个问题。
但您可能会考虑修改测试。我一般认为测试顺序导致脆弱的测试,因为它经常测试实现细节。
编辑:我不确定这是否解决了OP的问题。 Lucero的回答可能会更有帮助。
答案 3 :(得分:2)
看看这个blog post,它可以解决您的问题。
答案 4 :(得分:1)
否则你可以使用Callback函数并增加/存储callIndex值。
答案 5 :(得分:0)
从原始帖子我可以假设测试方法执行以下操作调用:
var screenOne = new Screen(...);
var screenTwo = new Screen(...);
var screens = new []{screenOne, screenTwo};
var screenManager = new ScreenManager(screens);
screenManager.Draw();
其中'Draw'方法的实现是这样的:
public class ScreenManager
{
public void Draw()
{
_screens[0].Draw();
_screens[1].Draw();
}
}
从我的角度来看,如果调用顺序非常重要,那么应该在系统中引入附加结构(描述序列)。
最简单的实现:每个屏幕都应该知道他的后续元素,并在绘制完成后调用其Draw方法:
// 1st version
public class Screen(Screen screenSubSequent)
{
private Screen _screenNext;
public Screen(Screen screenNext)
{
_screenNext=screenNext;
}
public void Draw()
{
// draw himself
if ( _screenNext!=null ) _screenNext.Draw();
}
}
public class ScreenManager
{
public void Draw()
{
_screens[0].Draw();
}
}
static void Main()
{
var screenOne = new Screen(null, ...);
var screenTwo = new Screen(screenOne, ...);
var screens = new []{screenOne, screenTwo};
var screenManager = new ScreenManager(screens);
}
从一点来看,每个Screen元素应该对另一个元素有所了解。这并不总是好的。如果是这样的话:你可以像'ScreenDrawer'那样创建一些类。这个对象将存储自己的屏幕和后续屏幕(可能从Screen类继承他。使用其他世界:'ScreenDrawer'类描述系统结构。这是最简单的实现方案:
// 2nd version
public class ScreenDrawer
{
private Screen _screenNext;
public ScreenDrawer(Screen screenNext, ...) : base (...)
{
_screenNext=screenNext;
}
public void Draw()
{
// draw himself
if ( _screenNext!=null ) _screenNext.Draw();
}
}
public class ScreenManager
{
public void Draw()
{
_screens[0].Draw();
}
}
static void Main()
{
var screenOne = new ScreenDrawer(null, ...);
var screenTwo = new ScreenDrawer(screenOne, ...);
var screens = new []{screenOne, screenTwo};
var screenManager = new ScreenManager(screens);
}
第二种方法引入了额外的继承,但不需要Screen类来了解他的子序列元素。
总结:两种方法都执行子序列调用,不需要“序列”测试。相反,他们需要测试当前的“屏幕”是否调用另一个并测试'ScreenManager'是否按顺序调用第一个元素的'Draw'方法。
这种方法:
感谢。