如何对包含Doctrine DBAL静态调用的函数进行单元测试
如何Mock Doctrine DBAL的DriverManager静态方法进行单元测试
针对你要测试的openNewConnection方法——它依赖DriverManager::getConnection这个静态方法创建数据库连接——我们可以通过Mock静态调用的方式,避免触发真实数据库连接,专注测试方法本身的逻辑。下面分享两种常用的实现方式:
方法一:用PHPUnit自带的静态Mock(PHPUnit 9.5+)
PHPUnit从9.5版本开始支持静态方法Mock,无需额外依赖,步骤如下:
use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\Connection; use PHPUnit\Framework\TestCase; class YourServiceTest extends TestCase { public function testOpenNewConnection_Success(): void { // 1. 创建Connection的Mock,模拟成功的连接实例 $mockConnection = $this->createMock(Connection::class); // 2. Mock DriverManager的静态getConnection方法 $this->mockStatic(DriverManager::class) ->method('getConnection') // 可指定预期参数,用anything()匹配任意参数 ->with($this->anything(), $this->anything()) ->willReturn($mockConnection); // 3. 实例化业务类并调用目标方法 $yourService = new YourService(); $resultConnection = $yourService->openNewConnection('test_database'); // 4. 断言返回的连接是我们的Mock实例 $this->assertSame($mockConnection, $resultConnection); } public function testOpenNewConnection_ThrowsException(): void { // 1. Mock DriverManager抛出连接失败的异常 $this->mockStatic(DriverManager::class) ->method('getConnection') ->willThrowException(new \Exception('Failed to connect')); // 2. 调用方法并验证异常处理逻辑 $yourService = new YourService(); $result = $yourService->openNewConnection('test_database'); // 根据实际catch逻辑调整断言,比如返回null或自定义错误 $this->assertNull($result); } }
方法二:用Mockery实现静态Mock
如果你的项目使用Mockery作为Mock工具,它通过alias:前缀可以轻松Mock全局静态类:
use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\Connection; use Mockery; use PHPUnit\Framework\TestCase; class YourServiceTest extends TestCase { // 测试后清理Mockery实例 protected function tearDown(): void { Mockery::close(); parent::tearDown(); } public function testOpenNewConnection_Success(): void { // 1. 创建Connection的Mock对象 $mockConnection = Mockery::mock(Connection::class); // 2. Mock DriverManager的静态getConnection方法 Mockery::mock('alias:' . DriverManager::class) ->shouldReceive('getConnection') ->once() // 验证方法被调用一次 ->with($this->anything(), $this->anything()) ->andReturn($mockConnection); // 3. 执行测试并断言 $yourService = new YourService(); $result = $yourService->openNewConnection('test_database'); $this->assertSame($mockConnection, $result); } public function testOpenNewConnection_HandleConnectionFailure(): void { // Mock DriverManager抛出异常 Mockery::mock('alias:' . DriverManager::class) ->shouldReceive('getConnection') ->once() ->andThrow(new \Exception('Connection error')); $yourService = new YourService(); $result = $yourService->openNewConnection('test_database'); // 根据你的catch逻辑断言结果 $this->assertNull($result); } }
额外注意事项
- 如果
$connection_params和$config是类的私有属性,建议通过构造函数注入或提供setter方法,方便测试时传入预期参数,让Mock的with()断言更精准。 - 测试异常场景时,记得覆盖catch块内的所有逻辑(比如日志记录、错误返回),确保所有代码分支都被测试到。
内容的提问来源于stack exchange,提问作者elb98rm
相关产品推荐
相关产品推荐

