如何使用数据库查询对对象进行单元测试

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (21)

我听说单元测试“非常棒”、“非常酷”和“各种好东西”,但我70%或更多的文件涉及数据库访问(有些是读的,有些是写的),我不知道如何为这些文件编写单元测试。

我正在使用PHP和Python,但我认为这是一个适用于大多数/所有使用数据库访问的语言的问题。

提问于
用户回答回答于

我建议模仿你对数据库的调用。模拟基本上是类似于您试图调用方法的对象的对象,因为它们具有调用者可以使用的相同属性、方法等。但是,在调用特定方法时,它将跳过这些操作,只返回一个结果,而不是执行它们被编程执行的任何操作。该结果通常提前定义。

为了设置对象以进行模拟,可能需要使用某种类型的控制/依赖项注入模式,如以下伪代码所示:

class Bar
{
    private FooDataProvider _dataProvider;

    public instantiate(FooDataProvider dataProvider) {
        _dataProvider = dataProvider;
    }

    public getAllFoos() {
        // instead of calling Foo.GetAll() here, we are introducing an extra layer of abstraction
        return _dataProvider.GetAllFoos();
    }
}

class FooDataProvider
{
    public Foo[] GetAllFoos() {
        return Foo.GetAll();
    }
}

现在,在单元测试中,可以创建FooDataProvider的模拟,它允许调用GetAllFoos方法,而不必实际命中数据库。

class BarTests
{
    public TestGetAllFoos() {
        // here we set up our mock FooDataProvider
        mockRepository = MockingFramework.new()
        mockFooDataProvider = mockRepository.CreateMockOfType(FooDataProvider);

        // create a new array of Foo objects
        testFooArray = new Foo[] {Foo.new(), Foo.new(), Foo.new()}

        // the next statement will cause testFooArray to be returned every time we call FooDAtaProvider.GetAllFoos,
        // instead of calling to the database and returning whatever is in there
        // ExpectCallTo and Returns are methods provided by our imaginary mocking framework
        ExpectCallTo(mockFooDataProvider.GetAllFoos).Returns(testFooArray)

        // now begins our actual unit test
        testBar = new Bar(mockFooDataProvider)
        baz = testBar.GetAllFoos()

        // baz should now equal the testFooArray object we created earlier
        Assert.AreEqual(3, baz.length)
    }
}

简单地说,这是一种常见的场景。当然,可能仍然希望对实际的数据库调用进行单元测试,为此将需要访问数据库。

用户回答回答于

理想情况下,对象应该是持久的无知。例如,应该有一个“数据访问层”,将向其发出请求,从而返回对象。这样,可以将该部分排除在单元测试之外,或者单独测试它们。

如果对象与数据层紧密耦合,则很难进行正确的单元测试。单元测试的第一部分是“单元”。所有单元都应该能够进行隔离测试。

在我的c#项目中,我使用NHibernate和一个完全分离的数据层。我的对象驻留在核心域模型中,并从我的应用层被访问。应用层与数据层和域模型层同时进行通信。

应用层有时也被称为“业务层”。

如果正在使用PHP,请创建一组特定的类数据访问。确保对象不知道它们是如何持久化的,并将两者连接到应用程序类中。

另一种选择是使用模拟/存根。

扫码关注云+社区