【问题标题】:Rhino Mocks: How to Mock a Database call in a Parameterless Method?Rhino Mocks:如何在无参数方法中模拟数据库调用?
【发布时间】:2016-10-05 20:02:10
【问题描述】:

我正在使用 NUnit 和 Rhino Mocks 为 C# 中的 ASP.NET MVC 应用程序编写单元测试。我在测试这个方法时遇到了一些问题:

public void Install()
    {
        Database.SetInitializer<DraftOrderObjectContext>(null);
        var dbScript = CreateDatabaseInstallationScript();

        Database.ExecuteSqlCommand(dbScript);
        SaveChanges();
    }

澄清一下,数据库不是指本地对象。第一个“Database.SetInitializer...”指的是:

System.Data.Entity.Database

而第二个“Database.ExecuteSqlCommand...”指的是:

System.Data.Entity.DbContext.Database

由于该方法没有返回任何内容,我认为制作一个模拟并验证 Database.ExecuteSqlCommand(dbScript); 就足够了至少被调用过一次。

现在我之前已经这样做了,但这涉及将数据库上下文传递给方法,这很容易模拟,但是在这种情况下没有参数。我需要找到一种方法来模拟“数据库”。


我已经尝试过像这样直接分配一个模拟:

System.Data.Entity.DbContext.Database = MockRepository.GenerateMock<System.Data.Entity.DbContext.Database>();

但这会破坏语法,因为该属性是只读的。


我也尝试过像这样模拟 DbContext:

System.Data.Entity.DbContext instance = MockRepository.GenerateMock<System.Data.Entity.DbContext>();

        instance.Expect(someCaller => someCaller.Database.ExecuteSqlCommand("sql"))
            .IgnoreArguments()
            .Return(1)
            .Repeat.Times(1);

但是我得到一个运行时错误,说 DbContext.getHashCode() 必须返回一个值。然后我尝试对 getHashCode 方法进行存根以使其返回某些内容,但这没有任何效果。


我对模拟还很陌生,所以我可能在这里遗漏了一些基本概念。如果是这样,我很抱歉。非常感谢任何帮助!

【问题讨论】:

  • 查看answer 的相关问题
  • 嗯,我不确定我是否可以使用该解决方案,因为我无法修改我需要测试的类。
  • 不确定是否有办法将其作为纯单元测试来执行 - DbContext.Database 不是虚拟的,因此经典的 Mocking 场景将无法工作。也许您需要为单元测试划清界限,并将其作为集成测试?

标签: c# unit-testing mocking nunit rhino-mocks


【解决方案1】:

恐怕这里唯一值得给出的答案是必须修改代码以使其对测试更加友好。尝试为调用static 类、属性或方法的方法编写单元测试并不是一项有价值或有价值的任务。您建议您可能在这里遗漏了一个基本概念,这可能是:static 是单元测试的最大敌人,集体智慧是,投入大量精力来测试使用静态资源的东西没有多大意义。只需重构代码即可。

如果重构代码真的不可能,那你为什么需要对它进行单元测试(这不是一个修辞问题,请评论)?如果担心您需要模拟这些对象作为其他测试的一部分,那么您应该使用测试友好的接口包装邪恶的、不可修改的代码并模拟它。

【讨论】:

  • 老实说,我刚刚开始了我作为软件开发人员的第一个职业角色,并被赋予了为公司的自定义 nopCommerce 插件编写单元测试的任务,所以我不确定他们是否会对我实际进入并修改可能破坏整个系统的核心功能感到满意。但是整个包装器的实现听起来确实很简单,我将在下次会议上提出这个问题,并征求他们的意见,看看他们是否可以接受,或者只是更愿意进行集成测试。
  • 测试是一个好主意的部分原因是它们会告诉您代码的某些部分何时可能设计不佳。老实说,如果你在我的团队会议上说“我想改进这门课,使其更可测试”,那么我会印象深刻并感激不尽。不过,您可能首先讨论它是明智的!祝你好运。 p.s.在我看来,让一个新开发人员为已经编写的代码编写单元测试有点残忍,商业价值有限。不要让它给你对 TDD 的第一印象不好,如果测试是先写的,那效果最好!
  • 为什么像这样的答案完全没有提到嘲笑static(或非virtual方法等)是一个已经解决的问题 i> 已经在几个模拟库中(特别是 TypeMock Isolator、JustMock、MS Fakes)?这个事实是不为人知的,还是只是“被遗忘”了?此外,当我们需要模拟某些东西时,我们真的应该更愿意妥协我们的代码以解决某些特定测试工具(例如,起订量)的限制吗?
  • 删除对静态方法的调用不会损害您的代码,而是改进它。此外,您提到的工具应仅用于非常特定的情况。一个这样的工具,PowerMock,在他们自己的 github 文档中声明:“请注意,PowerMock 主要面向具有单元测试专业知识的人。把它交给初级开发人员可能弊大于利。”因此,我认为建议像 Reddy 这样的新开发人员将这些工具用作第一个停靠点是不合适的,这就是为什么我在回答中没有提及它们。
  • 此外,这些工具通常通过修改已编译的代码来工作,这会引发您甚至没有测试生产中使用的类的版本的问题。虽然我不否认这有时会很有用(尽管我个人从来没有真正需要过),但它只是感觉是应该尽可能避免的事情,这在这种情况下,它是。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多