Rhino Mocks:如何在无参数方法中模拟数据库调用?

时间:2016-10-05 20:02:11

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

我正在使用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

由于该方法没有返回任何内容,我认为做一个mock并验证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方法存根,使其返回一些但没有效果的东西。

我仍然相当嘲笑,所以我可能会错过一些基本概念。如果是这样,我道歉。非常感谢任何帮助!

1 个答案:

答案 0 :(得分:1)

我担心唯一值得给出的答案是必须修改代码以使其更加适合测试。尝试为调用 let inputData:Data = "{\"data\": [{\"id\":\"x\"},{\"id\":\"y\"},{\"id\":\"z\"}]}".data(using: .utf8)! if let response = try JSONSerialization.jsonObject(with: inputData, options: []) as? [String:AnyObject], let responseData = response["data"] as? [AnyObject] { for (index, item) in responseData.enumerated() { let id = item["id"] as! String print(id) } } 类,属性或方法的方法编写单元测试并不是一项有益或有价值的任务。你建议你可能在这里错过了一个基本概念,这可能是它:static是单位测试的最大敌人,集体智慧是没有太多的努力付出很多努力测试使用静态资源的东西。只需重构代码。

如果重构代码真的不可能,那你为什么需要对它进行单元测试(这不是一个修辞问题,请评论)?如果担心你需要在其他测试中模拟这些对象,那么你应该用一个测试友好的界面包装邪恶的,不可修改的代码,然后嘲笑它。