犀牛模拟框架AAA快速入门?

11

我一直在寻找关于如何使用 AAA 语法的 Rhino Mocks 3.5+ 的相关信息。我发现很多博客中介绍了新旧版本混合的内容,这似乎让学习变得更加困难。

如果有一个 Rhino Mocks AAA Cheat Sheet(类似于早期版本),那就太棒了。难道您需要知道有关旧版本 Rhino 的所有内容才能使用更新版本吗?我相信如果我是一名专家,我会喜欢 Rhino 中的所有功能,但目前我只是被海量信息淹没。任何指针或好链接都将不胜感激!

4个回答

13

1
+1:很好的快速参考。我喜欢它。相当完整。这可能不是理解概念的好开始,但它很棒,可以记住语法并了解可能性。 - Stefan Steinegger

1

我假设你已经熟悉官方文档,在我看来这是相当不错的。 我的建议是尝试使用Rhino Mocks,在遇到更具体的问题时可以在SO或其他地方搜索解决方案。我认为没有全面的Rhino Mocks速查表。我猜你问“如何使用Rhino Mocks实现这个和那个”会有更多的运气。

编辑: 嗯,当针对AAA时,您不需要使用Record / Playback。 AAA涉及三个步骤:

  • 安排(Arrange),用于设置模拟类的行为,例如

.

IOmicronDll mockWrapper = MockRepository.GenerateMock<IOmicronDll>();
mockWrapper.Expect(wrapper => wrapper.Lock(1, ref errors)).OutRef(string.Empty).Return(true).Repeat.Any();
mockWrapper.Expect(wrapper => wrapper.Exec(1, "sys:cfg?(type)", ref output, ref errors)).OutRef("1,CMC 56,0;", "").Return(true).Repeat.Any();
mockWrapper.Expect(wrapper => wrapper.Exec("1", "sys:cfg?(type)", ref output, ref errors)).OutRef("1,CMC 56,0;", "").Return(true).Repeat.Any();
Microsoft.Practices.Unity.UnityContainer c = new Microsoft.Practices.Unity.UnityContainer();
c.RegisterInstance<IOmicronDll>(mockWrapper);
  • Act,代表执行测试

    public Omicron(int deviceID)
    {
        try
        {
            if (g_Omicron == null)
                g_Omicron = Microsoft.Practices.ServiceLocation.ServiceLocator.Current.GetInstance<CMEngineWrapper.IOmicronDll>();
            m_UniqueIdentifier = Guid.NewGuid();
            m_Logger = Microsoft.Practices.ServiceLocation.ServiceLocator.Current.GetInstance<AdvAdmittance.Framework.ILogger>();
            m_ID = deviceID;
            GetConfiguration();
            g_InstancesCount++;
            m_PollThread = new Thread(new ThreadStart(DoPoll));
            m_PollThread.Start();
        }
    
  • Assert则代表验证结果

.

Assert.AreEqual("CMC 56", omicron.Type);
mockWrapper.AssertWasCalled(wrapper => wrapper.Release(), options => options.Repeat.AtLeastOnce());

也许以上的例子不是最好的,但可能会让你朝着正确的方向前进。


谢谢,没错 - Ayende确实有一些很棒的东西。作为一个想要学习如何使用Rhino进行AAA的新手,似乎我需要使用录制/回放来完成,然后再提出如何以AAA风格完成特定问题的具体问题?当然,我必须先学会录制/回放。这就是我困惑的地方,甚至不知道从哪里开始问一个好问题。 - Bill Campbell
2
我的建议是完全跳过录制/回放。我认为AAA语法更清晰、更易于理解,而且你实际上不需要知道过去是如何使用R/P完成的。首先编写一些简单的单元测试,并按照你认为Rhino工作的方式进行断言。这将帮助你练习AAA语法。 - Igor Brejc
2
AAA 的想法是在开始时设置带有行为的存根,并在结束时进行断言(如您链接的文档中所示)。但是,您正在使用模拟而不是存根,在开始时设置期望,而且这些期望甚至从未得到验证,因为您没有在任何地方使用“VerifyAllExpectations”。从 Bill 的后续问题 http://stackoverflow.com/questions/2349454/rhinomocks-aaa-syntax/2350864#2350864 中可以看出您已经让他感到困惑。 - Wim Coenen
@Wim Coenen - 如果您查看他的期望值,他有Repeat.Any(),这意味着无需调用VerifyAllExpectations()。 - Pedro

1

首先确保您知道AAA中每个A的含义。您可能已经知道,但为了完整回答,我将包括我的工作定义:

  • 安排是我设置输入、模拟/存根、具有待测试方法的对象的地方
  • 行动是我调用待测试方法的地方
  • 断言是我验证是否按照预期发生或未发生的地方

我喜欢在我的测试代码中添加注释,以提醒自己考虑这些事情。一个例子可能有助于澄清:假设我有一个服务层类,它使用两个提供程序层类,一个来自“旧”系统,另一个来自“新”系统;我正在测试将旧事物复制到新系统的方法,该方法为每个找到的旧事物调用“CreateThing”方法一次。

[Test]
public void Should_create_new_Thing_for_each_old_Thing()
{
  // -----
  // arrange

  // hardcode results from old system provider
  List<Thing> oldThings = new List<Thing> { ... };

  // old system provider
  var oldProvider = MockRepository.GenerateStub<IOldSystemProvider>();
  oldProvider.Stub(m=>m.GetThings()).Return(oldThings);

  // new system provider
  var newProvider = MockRepository.GenerateStub<INewSystemProvider>();

  // service object
  var svc = new MyService(oldProvider, newProvider);

  //-----------
  // act
  var result = svc.CopyThings();

  //------------
  // assert
  oldThings.ForEach(thing => 
                    newProvider.AssertWasCalled(prov => prov.CreateThing(thing)));
}

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接