PHPUnit 4.8 Mock mysql 数据库接口

Posted

技术标签:

【中文标题】PHPUnit 4.8 Mock mysql 数据库接口【英文标题】:PHPUnit 4.8 Mock mysql database interface 【发布时间】:2018-04-20 06:27:28 【问题描述】:

下午好,

我有一堆使用旧的mysql 库(例如mysql_query($sql))的遗留代码,我正在尝试用phpUnit 对其进行测试(4.8 是由于各种原因在服务器上运行的最新版本)。

有谁知道如何模拟这个数据库连接,以便在运行预定查询时返回预定结果?我尝试使用 getConnection()(根据此处的文档:http://devdocs.io/phpunit~4/database)无济于事。

例如我有这个类:

class Raffle 
    ...
    public static function loadAll($filter="")
        //$filter = mysql_real_escape_string($filter); // protect against SQL injection
        $raffles = []; // the array to return

        $sql = "SELECT * FROM raffles $filter;"; // include the user filter in the query
        $query = mysql_query($sql);

        //echo mysql_error();

        while($row = mysql_fetch_assoc($query))
            $raffles[] = Raffle::loadFromRow($row); // generate the raffe instance and add it to the array
        
        return $raffles; // return the array
    
    ...

mysql_connect() 调用是在一个名为 db.php 的文件中完成的,该文件会加载到需要它的每个页面上,而不是在类文件本身中。)

提前致谢。

【问题讨论】:

你能给我们看一些代码吗,比如连接是如何创建的,它是由 DI 传递的吗?直接在那个使用的类中实例化呢?它可以帮助我们。 不确定您所说的 DI 是什么意思,但基本上有一个文件调用 mysql_connect() 并带有凭据,然后将其导入每个公共页面。因此,当在页面上加载类时,mysql 连接已经打开。我几乎设法用一种有趣的 Mocking 方法解决了这个问题。如果它有效,我将在明天将其发布为答案:-)!。谢谢! by DI 我谈到了依赖注入,请展示你的代码,它比文字更有效地解释一个问题,并找到了解决方案。向我们展示您要测试的功能/方法以及创建连接的方式/位置。好的,祝你好运。 谢谢,我还是添加了代码:-) 【参考方案1】:

对于其他陷入这种情况的人,我发现为 PDO 构建一个包含功能 api 回退的模拟允许我将代码迁移到基于可测试 OO 的模型,同时仍然使用旧的 mysql 库.

例如:

// the basic interfaces (function names taken from PDO
interface DBConnAdapter 
    public function query($sql);

// since PDO splits connections and statements the adapter should do the same
interface DBQueryAdapter 
    public function num_rows();
    public function fetch_assoc();

...
class DBAdapter implements DBConnAdapter 

    public function query($sql)
        $query = mysql_query($sql); // run the query using the legacy api
        return $query ? new QueryAdapter($query) : false; // return a new query adapter or false.
    


...
// an example of a basic mock object to test sql queries being sent to the server (inspired by mockjax :-) ) 
class DBMock implements DBConnAdapter 

    public $queries = []; // array of queries already executed
    public $results = []; // array of precomputed results. (key is SQL and value is the returned result (nested array))

    public function query($sql) 
        if($this->results[$sql])
            $query = new DBQueryMock($sql, $this->results[$sql]); // a mock of PDOStatement that takes the sql it ran and the results to return
            $queries[] = $query; // add the query to the array
            return $query; // return the query
        
        return false; // we do not know the statement so lets pretend it failed
    
    // add a result to the list
    public function add_single_result($sql, $result)
        // check if the index was set, if not make an array there
        if(!isset($this->results[$sql])) $this->results[$sql] = [];
        // add the result to the end of the array
        $this->results[$sql][] = $result; 
        // return its index
        return count($this->results[$sql]) - 1;
    

诚然,这不是一个理想的解决方案,因为它需要修改代码以支持适配器对象并删除一些功能(例如mysql_real_escape_string),但它确实有效......

如果您有更好的解决方案,请分享 :-) 谢谢!

【讨论】:

以上是关于PHPUnit 4.8 Mock mysql 数据库接口的主要内容,如果未能解决你的问题,请参考以下文章

PHPUnit:使用Mock修改返回值?

PHPUnit Mock 多种不同的方法

PHPUnit “模拟方法不存在。”当使用 $mock->expects($this->at(...))

phpunit mock - 方法不存在

PHPUnit Mock Objects 默认情况下从不期望

PHPUnit Mock稍后改变期望