PHPUnit中同一方法多次调用返回不同结果的正确测试方式
问题:如何测试同一方法(
getNextUniqueBunch)使其返回不同结果? function exampleQuestion() { $rows = []; $rowsAgain = []; while ($bunch = $this->_dataSourceModel->getNextUniqueBunch()) { $rows[] = $bunch; } //执行一些修改后,getNextUniqueBunch将返回不同结果 while ($bunch = $this->_dataSourceModel->getNextUniqueBunch()) { $rowsAgain[] = $bunch; } }
用户尝试的方案1
public function importDataProvider(): array { return [ [ [ '_email' => 'jondoe@example.com', '_website' => 'base', '_store'=> 'admin', '_entity_id' => 'abc' ] ], [ [ '_email' => 'jondoe@example.com', '_store' => 'admin', '_entity_id' => 'abc' ] ] ]; } /** * @dataProvider importDataProvider * @return void */ public function testImportData($data) { $this->dataSourceModel->expects($this->any()) ->method('getNextUniqueBunch') ->withConsecutive([], []) ->willReturnOnConsecutiveCalls([$data], [$data]); $mockClassObj->exampleQuestion(); }
该方案中,第一次调用
getNextUniqueBunch返回数组,但第二次调用返回空数组,无法满足第二次循环获取数据的需求。
用户尝试的方案2
修改代码后,第二次调用getNextUniqueBunch可正常返回结果:
$this->dataSourceModel->expects($this->at(3)) ->method('getNextUniqueBunch') ->withConsecutive([], []) ->willReturnOnConsecutiveCalls([$data], [$data]);
此方案使用了已弃用的
$this->at(3),虽然能让第二次调用返回数据,但不符合PHPUnit的最佳实践。
正确实现方式
问题核心是要模拟两次完整的循环调用序列:第一次循环先返回数据,再返回空值终止循环;第二次循环再次返回新数据,再返回空值终止循环。直接用PHPUnit的willReturnOnConsecutiveCalls按调用顺序指定所有返回值即可,无需依赖弃用的at()方法:
/** * @dataProvider importDataProvider * @return void */ public function testImportData($dataFirstLoop, $dataSecondLoop) { // 按调用顺序指定返回值:第一次循环返回数据→空值终止;第二次循环返回新数据→空值终止 $this->dataSourceModel->expects($this->exactly(4)) ->method('getNextUniqueBunch') ->willReturnOnConsecutiveCalls( [$dataFirstLoop], // 第一次循环取数 null, // 第一次循环终止 [$dataSecondLoop], // 第二次循环取数 null // 第二次循环终止 ); $mockClassObj->exampleQuestion(); // 可添加断言验证结果,示例: // $this->assertEquals([[$dataFirstLoop]], $mockClassObj->rows); // $this->assertEquals([[$dataSecondLoop]], $mockClassObj->rowsAgain); } // 调整数据提供者,提供两次循环的不同数据 public function importDataProvider(): array { return [ [ // 第一次循环返回的数据 [ '_email' => 'jondoe@example.com', '_website' => 'base', '_store'=> 'admin', '_entity_id' => 'abc' ], // 第二次循环返回的数据 [ '_email' => 'jondoe@example.com', '_store' => 'admin', '_entity_id' => 'abc' ] ] ]; }
关键说明:
$this->exactly(4)明确指定方法被调用4次,避免any()带来的匹配模糊问题;willReturnOnConsecutiveCalls严格遵循业务代码中两次循环的调用顺序返回对应值;- 若
getNextUniqueBunch无数据时返回空数组而非null,只需把代码中的null替换为[]即可。
内容的提问来源于stack exchange,提问作者rocky
相关产品推荐
相关产品推荐

