Stub和Mock在单元测试中的区别

11

最近我对测试非常感兴趣,现在正在努力学习如何以最佳方式进行单元测试。 我使用NUnit和Rhino Mocks。 我还在Stackoverflow上阅读了很多内容,但没有找到明确答案。

我想知道的是,如果我有一个像下面这样的方法,我应该模拟OfficeClass依赖项并测试GetAllOffices,还是仅使用依赖项的存根,并验证已调用方法GetAllOffices,并且我确实从存根的设置中获取了预期的办公室?

public Offices GetAllOffices() 
{
    try
    {
        var offices = officeClass.GetAllOffices();
        return offices;
    }
}

当OfficeClass只是另一个POCO时,与其作为Web服务相比,是否会有任何区别,例如在模拟与存根测试方面?

长话短说:什么情况下使用模拟,什么情况下使用存根进行单元测试?


我之前读过那篇文章,但我仍然不确定何时使用其中一个而不是另一个,因此我认为在我的代码环境中获得一些输入会有所帮助。 - Daniel Hansen
不确定您在这篇文章中缺少什么 - 所有内容都在那里。它列出了这两个概念之间的所有差异。 - BartoszKP
我仍然觉得我没有回答这个问题:“在单元测试中何时使用Mock和Stub?”我认为我已经意识到了两者之间的区别,但是不知道在什么情况下应该mock或stub一个对象。 - Daniel Hansen
1个回答

11

模拟使用框架来生成一个“模拟对象”。例如,如果officeClass是您的数据存储库,则可以使用模拟框架(我使用MOQ)来生成一个存储库的模拟。这就是为什么使用接口作为依赖项进行测试是理想的,模拟框架可以轻松地为测试生成接口的模拟。

至于存根,据我了解,您需要手动替换依赖项并创建预置响应。例如,如果您有一个名为IOfficeClass的接口,并且您创建了一个从它继承的新类,您可以将该类注入到服务中以允许您使用它。

同样,像Web服务这样的事物应该包装在某个接口中(例如IRepository模式),这将使您能够轻松地测试逻辑而无需连接到Web服务。POCO类也是如此。

因此,例如,在您的情况下,您将拥有:

public interface IOfficeRepository
{
    IQueryable<Office> GetAll();
}

为您服务

public class MyOfficeService
{
    private readonly IOfficeRepository officeRepostiory;

    public MyOfficeService(IOfficeRepository repository)
    {
        this.officeRepostiory = repository;
    }

    public Office GetOffice(int id)
    {
        return this.officeRepostiory.GetAll().SingleOrDefault(o => o.Id == id);
    }
}

这样做,您可以更改底层数据源而无需修改主要应用程序或业务逻辑代码。

使用moq,您的单元测试将类似于以下内容:

[TestClass]
public class OfficeUnitTest
{
    private MyOfficeService service;

    [TestInitialize]
    public void Setup()
    {
        var officeRepository = new Mock<IOfficeRepository>();

        var office = new List<Office>();
        office.Add(new Office{ Id = 1 });

        officeRepository.Setup(m => m.GetAll()).Returns(office.AsQueryable());

        this.service = new MyOfficeService(officeRepository.Object);
    }

    [TestMethod]
    public void TestGetById()
    {
        Assert.IsNotNull(service.GetOffice(1));

        // my mock will never return a value for 2
        Assert.IsNull(service.GetOffice(2));
    }
}

以下可以了解有关mock和stub的更多信息:

http://martinfowler.com/articles/mocksArentStubs.html

http://msdn.microsoft.com/en-us/library/ff649690.aspx


我认为_martinfowler_的解释很好地阐述了关于DummyFakeStubsMocks的四个含义。谢谢。 - tech_me

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