如何对业务逻辑和数据访问代码进行单元测试

时间:2014-01-28 21:37:41

标签: php database unit-testing

我在一个PHP项目中工作,其中测试软件被忽略了很长时间。 业务逻辑充满了硬编码的依赖关系,并通过一些手工制作的(Oracle)SQL立即访问数据库。

由于复杂的数据库设置,对(复杂)数据库夹具的严密压缩以及缺少内存中的解决方案,我已经放弃了尝试构建自动化集成测试。

对我来说,它似乎是最好的起点,就是测试业务逻辑。因此,我想重构代码以从业务逻辑中分离出数据访问代码。我仍然在谈论一些基本的设计问题:

  1. 封装/摆脱这个复杂SQL的首选方法是什么? 是否有任何设计模式,它对如何以可配置的方式从数据源获取数据有一些很好的提示?在某些情况下,注入Propel Active Query对象似乎是有帮助的,但在复杂的情况下,我猜它们很难模拟。
  2. 对于需要大量使用其数据库的应用程序的软件架构+单元测试是否有好的

1 个答案:

答案 0 :(得分:1)

回答你的第二个问题:你需要Working Effectively with Legacy Code:它解释了几种破坏依赖关系以使代码可测试的模式。

关于你的第一个问题:这取决于你目前的情况。以下是本书中深入介绍的一些示例:

示例1 - 提取并覆盖调用

如果你有一个类似的问题(例如在php中没有#n,那么你会得到这个想法)

class MyClass {
    int getNbEligibleItems(){
      List<Item> rawItems = readInDb();
      //Now count elegible ones
    }

    List<Item> readInDb(){
      //Directly call DB and return a raw list
    }
}

然后你可以使readInDb虚拟,并在测试中使用模拟:

class TestableMyClass : MyClass {
    override List<Item> readInDb(){
       //Return a list of hard code test items
    }
}

示例2 - 参数化构造函数

如果你有这样的课程

class MyClass {
    private IDbReader _reader;

    MyClass(){
       _reader = new DbReader();
    }

    int work(){
       List<item> items = _reader.read();
       //Work with items
    }
}

然后可以将构造函数更改为

    MyClass() : this(new DbReader()){ }

    MyClass(IDbReader reader){
       _reader = reader;
    }

因此可以在测试中模拟db

所以,简而言之:有很多技术可以帮助你的情况。我们&#39;需要一些代码更具体。我推荐阅读这本书,因为它提供了很多答案。