You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用WP_Mock和Mockery模拟$wpdb->prefix属性?

环境信息
工具/框架版本
PHP7.4
WordPress6.2
WP_Mock1.0
PHPUnit9.6.11
Mockery1.6.6

问题重现

测试用例代码

use PHPUnit\Framework\TestCase;
use WP_Mock;
use Mockery;

class WPAB_Database_Service_Test extends TestCase
{
  /**
   * @test
   */
  public function migrate()
  {
    // ... 其他初始化代码 ...

    $wpdb_mock = Mockery::mock('WPDB');

    $wpdb_mock
      ->allows('get_charset_collate')
      ->withNoArgs()
      ->andReturn('utf16_general_ci');

    $wpdb_mock->prefix = 'wpbb_';

    $result = $database_service->migrate(); // 待测试方法

    $this->assertSame($result, 1);
  }
}

待测试代码中的问题行

$prefix = $wpdb->prefix;

问题现象

运行测试时抛出警告:

PHP Notice: Undefined property: Mockery_1__WPDB::$prefix in ...

测试意外通过,推测Mockery对未模拟的属性默认返回空字符串。

解决方案:模拟属性的正确方式

一、Mockery 模拟非静态属性

直接给Mock对象赋值属性会因为Mockery的代理机制失效,必须通过Mockery的API来声明属性访问:

方式1:宽松模拟(仅返回值,不验证访问次数)

$wpdb_mock = Mockery::mock('WPDB');
// 模拟prefix属性的读取
$wpdb_mock->allows('prefix')->andReturn('wpbb_');

// 保留原有方法的模拟
$wpdb_mock
  ->allows('get_charset_collate')
  ->withNoArgs()
  ->andReturn('utf16_general_ci');

方式2:严格模拟(验证属性是否被访问)

如果需要确保属性被正确读取,可以用shouldReceive添加访问次数断言:

$wpdb_mock = Mockery::mock('WPDB');
// 断言prefix属性被读取1次
$wpdb_mock->shouldReceive('prefix')->once()->andReturn('wpbb_');

二、Mockery 模拟静态属性

针对类的静态属性,需要用mockStatic方法处理:

// 模拟WPDB类的静态属性$static_prefix
Mockery::mockStatic('WPDB')
  ->shouldReceive('static_prefix')
  ->andReturn('wp_static_');

三、结合WP_Mock 模拟WordPress全局对象

WP_Mock专为WordPress生态设计,模拟全局$wpdb这类对象更贴合场景:

public function setUp(): void
{
    WP_Mock::setUp();
    
    // 模拟全局$wpdb对象及其属性、方法
    WP_Mock::userFunction('get_global', [
        'args' => ['wpdb'],
        'return' => (object) [
            'prefix' => 'wpbb_',
            'get_charset_collate' => fn() => 'utf16_general_ci'
        ]
    ]);
}

public function tearDown(): void
{
    WP_Mock::tearDown();
    Mockery::close();
}

// 测试方法中直接使用全局$wpdb即可
public function migrate()
{
    // ... 初始化$database_service ...
    $result = $database_service->migrate();
    $this->assertSame($result, 1);
}

四、避免警告的最佳实践

  1. 禁止直接给Mock对象赋值属性:必须通过Mockery/WP_Mock的API声明属性访问逻辑,避免触发未定义属性警告。
  2. 优先用WP_Mock处理WordPress全局对象:WP_Mock提供的API更适配WordPress的全局变量、函数体系,减少Mockery的使用复杂度。
  3. 启用Mockery严格模式:确保所有被访问的属性/方法都被提前模拟,避免测试意外通过:
$wpdb_mock = Mockery::mock('WPDB')->shouldBeStrict();

内容的提问来源于stack exchange,提问作者4uruanna

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 00:11:22