【问题标题】:ci_phpunit_test: Help needed about test double with queriesci_phpunit_test:需要关于带查询的测试替身的帮助
【发布时间】:2025-12-11 01:00:02
【问题描述】:

我正在学习使用 CodeIgniter 进行单元测试,我想问一些有关使用 Mocks 类测试查询的问题。

我尝试使用 get_news_all() 方法实现以下类 News_model,该方法返回表 'news' 中的所有新闻数据,而 get_news 仅返回同一标题和文本字段。

class News_model extends CI_Model
{
public function __construct(){
    $this->load->database();
}

public function get_news_all()
{
    $query=$this->db->get('news');
    $result=$query->result_array();
    return $result;
}

public function get_news()
{
    $this->db->select('title, text');
    $this->db->from('news');
    $query=$this->db->get();
    $result=$query->result_array();
    return $result;
}

在我尝试为测试方法 get_news_all() 构建 News_model_with_mocks_test 之后,在这种情况下测试运行良好:

class News_model_with_mocks_test extends TestCase
{
public function setUp()
{
    $this->resetInstance();
    $loader=$this->getMockBuilder('CI_Loader')->setMethods(['database'])->getMock();
    $loader->method('database')->willReturn($loader);
    $this->CI->load=$loader;
    if(!class_exists('CI_DB', false))
    {
        eval('class CI_DB extends CI_DB_query_builder {}');
    }
    $this->obj=new News_model();
}

public function test_1()
{
    $result_array = [
            [
                    "id" => "1",
                    "title" => "News",
                    "slug" => "news",
                    "text" => "News",
            ],
            [
                    "id" => "2",
                    "title" => "News2",
                    "slug" => "news2",
                    "text" => "News2",
            ],
    ];
    $db_result=$this->getMockBuilder('CI_DB_result')->disableOriginalConstructor()->getMock();
    $db_result->method('result_array')->willReturn($result_array);
    $db = $this->getMockBuilder('CI_DB')->disableOriginalConstructor()->getMock();
    $db->expects($this->once())->method('get')->with('news')->willReturn($db_result);
    $this->obj->db=$db;
    $result=$this->obj->get_news_all();
    $this->assertEquals($result_array,$result);
}

}

但我不知道如何对 get_news() 方法进行测试,我尝试了这样的方法:

public function test_1()
{
    $result_array2 = [
            [
                    "title" => "News",
                    "text" => "News",
            ],
            [
                    "title" => "News2",
                    "text" => "News2",
            ],
    ];
    $db_result=$this->getMockBuilder('CI_DB_result')->disableOriginalConstructor()->getMock();
    $db_result->method('result_array')->willReturn($result_array2);
    $db = $this->getMockBuilder('CI_DB')->disableOriginalConstructor()->getMock();
    $db->expects($this->once())->method('query')->with('select title,text from news')->willReturn($db_result);
    $this->obj->db=$db;
    $result=$this->obj->get_news();
    $this->assertEquals($result_array2,$result);
}

phpunit 抛出以下异常:

PHP Fatal error:  Call to a member function result_array() on a non-   object in /opt/lampp/htdocs/codeigniter/application/models/Users_model.php on line 21

我不知道如何使用选择查询来测试双精度!提前感谢您的回答。

【问题讨论】:

    标签: php mysql codeigniter unit-testing


    【解决方案1】:

    这几天我阅读了更多文档,我明白这对我来说是对 Mocks 使用的误解。换句话说,我们必须定义我们期望的方法和返回值,并将它们注入原始类。这是我上面写的News_model类的get_users方法:

    public function get_news()
    {
        $this->db->select('title, text');
        $this->db->from('news');
        $query=$this->db->get();
        $result=$query->result_array();
        return $result;
    }
    

    我们只是希望 get() 方法返回一个结果数组,其中只包含每条记录的标题和文本字段:

    class News_model_with_mocks_test extends TestCase
    {
    public function setUp()
    {
        $this->resetInstance();
        $loader=$this->getMockBuilder('CI_Loader')->setMethods(['database'])->getMock();
        $loader->method('database')->willReturn($loader);
        $this->CI->load=$loader;
        if(!class_exists('CI_DB', false))
        {
            eval('class CI_DB extends CI_DB_query_builder {}');
        }
        $this->obj=new News_model();
    } 
    
    public function test_1()
    {
        $result_array = [
                [
                        "title" => "News test",
                        "text" => "News text",
                ],
                [
                        "title" => "News2",
                        "text" => "Testo news2",
                ],
        ];
        $db_result=$this->getMockBuilder('CI_DB_result')->disableOriginalConstructor()->getMock();
        $db_result->method('result_array')->willReturn($result_array);
        $db = $this->getMockBuilder('CI_DB')->disableOriginalConstructor()->getMock();
        $db->expects($this->once())->method('get')->willReturn($db_result);
        $this->obj->db=$db;
        $result=$this->obj->get_news();
        $this->assertEquals($result_array,$result);
    }
    }
    

    我希望这个解决方案可以帮助有同样疑问的人!

    【讨论】:

      最近更新 更多