首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Stubs和Mocks的正确方法是什么?

使用Stubs和Mocks的正确方法是什么?
EN

Stack Overflow用户
提问于 2011-09-06 16:14:03
回答 4查看 693关注 0票数 11

下面是我的例子:

代码语言:javascript
复制
[TestMethod]
public void NewAction_should_return_IndexAction()
{
    NewViewModel viewModel = new NewViewModel()
    {
        Name = "José Inácio Santos Silva",
        Email = "joseinacio@joseinacio.com",
        Username = "joseinacio"
    };

    //IsUserRegistered is used to validate Username, Username is unique.
    _mockAuthenticationService.Setup(x => x.IsUserRegistered(viewModel.Username )).Returns(false);

    //IsUserRegistered is used to validate Email, Email is unique.
    _mockUsuarioRepository.Setup(x => x.GetUserByEmail(viewModel.Email));
    _mockDbContext.Setup(x => x.SaveChanges());
    _mockUsuarioRepository.Setup(x => x.Add(It.IsAny<User>()));

    _userController = new UserController(_mockUsuarioRepository.Object, _mockDbContext.Object, _mockAuthenticationService.Object);

    ActionResult result = _userController.New(viewModel);

    result.AssertActionRedirect().ToAction("Index");

    _mockAuthenticationService.VerifyAll();
    _mockUsuarioRepository.VerifyAll();
    _mockDbContext.VerifyAll();
}

我读过一些教程,他们说我们应该使用,每个测试只使用一个模拟。

但是看看我的测试,它使用3个模拟,检查我的Action是否按照我需要检查这3个模拟的正确方式工作,不同意吗?

我怎样才能以正确的方式做这个测试?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-09-06 16:17:53

每个单元测试应该只测试一件事情。

在单元测试中,您正在测试三个模拟对象。如果mockAuthenticationService失败,这将被报告,单元测试将停止在那里。其他模拟对象的任何错误都不会被报告,而且实际上是隐藏的。

在这种情况下,您应该创建三个单元测试,在每个单元测试中只验证一个Mock对象。剩下的只是用作存根。(存根与模拟对象完全相同,只是末尾不调用VerifyAll )

为了避免重复和浪费精力,您应该重构该单元测试,以便大多数代码位于一个单独的方法中。三个单元测试中的每一个都调用此方法,然后验证单个模拟。

您还需要进行测试,以确保调用正确的重定向。这也应该是一个单独的测试。

很简单:

代码语言:javascript
复制
[TestMethod]
public void NewAction_should_checkUserRegistered()
{
    SetupTest();
    _mockAuthenticationService.VerifyAll();
}

[TestMethod]
public void NewAction_should_GetUserByEmail()
{
    SetupTest();
    _mockUsuarioRepository.VerifyAll();
}

[TestMethod]
public void NewAction_should_SaveDBContext()
{
    SetupTest();
    _mockDbContext.VerifyAll();
}

[TestMethod]
public void NewAction_should_return_Redirects_Action()
{
    var novoActionResult = SetupTest();
    novoActionResult.AssertActionRedirect().ToAction("Index");
}
票数 4
EN

Stack Overflow用户

发布于 2011-09-06 16:40:35

简短的回答:“每次测试只有一个模拟。”模棱两可。尽可能多地使用伪代码,以便将测试中的代码隔离到测试一个条件的“单元”中。它应该是这样的:每次测试只测试一件东西。如果您正在检查多个模拟对象的状态,则可能测试的对象不止一个。

较长的答覆:

这里有很多需要回答的地方,以便按照我所遇到的最佳实践编写单元测试。

通用术语来自(单元测试的艺术),我希望这一术语将变得通用:

伪--一个将被测试代码与应用程序的其他部分隔离开来的对象。

Stub -一个简单的假对象。

Mock --一个存储传递给它的内容的假对象,您可以对它进行检查以验证测试。

存根和毛皮都是假的。

“每个测试只有一个模拟”,错了。您可以使用尽可能多的伪码来将测试中的代码与应用程序的其余部分完全隔离开来。如果一个方法不需要参数,就没有什么可以伪造的。如果一个方法采用简单的数据类型,例如intstring,它没有任何复杂的行为,您不需要伪造它。如果您有两个存储库,上下文,一个服务对象传入,伪造所有它们,所以没有其他的生产方法被调用。

您应该像@Mongus所说的那样,每个测试都有一个条件。

测试命名约定:在本例中,MethodUnderTest_Condition_ExpectedBehaviour不能这样做,因为您已经测试了多个条件。

测试模式:排列,动作,断言。从您的测试来看,这似乎就是您所做的,但您正在安排使用私有成员。您应该在每个测试中用变量替换这些变量,因为测试的运行顺序并不总是被强制执行,因此无法保证这些变量的状态,从而使您的测试不可靠。

买一本“单元测试的艺术”( that ) http://artofunittesting.com/ --它将回答你更多的问题,是一项很好的投资;如果办公室着火,我会拿一本书。

票数 2
EN

Stack Overflow用户

发布于 2011-09-06 16:17:50

IMHO的模拟和存根并不是唯一定义的--每个作者使用它们的方式略有不同。

正如我所理解的,存根“模拟”行为或“输出”,而您使用模拟,例如,检查“输入”到模拟对象/接口(如MOQ中的验证-方法)。

如果您这样看的话,我也认为您应该只使用一个Mock,因为您应该只测试一件事情--如果您看到它更像注入可测试接口的存根,那么就不可能这样做。

如果这里确实需要VerifyAll,那么您确实使用了3种模拟,但我不认为它们是嵌套的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7322980

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档