Laravel 8单元测试调用Helper返回null及测试数据库配置问题咨询
问题修复方案
问题根源
你遇到的报错核心原因是测试环境默认使用sqlite内存库,配合RefreshDatabase trait运行测试时,会初始化一个完全空白的数据库。你的Helper::getRandParticipant方法大概率是读取数据库的参与者数据,业务代码运行时用的是有数据的开发/生产库,所以返回正常;测试环境没有预先生成的参与者数据,方法查询不到内容返回null,后续读取participant属性时就抛出了错误,和数据库类型没有关系。
关于测试数据库的疑问解答
- 不需要把测试数据库换成MySQL,sqlite内存库运行速度更快,完全满足单元测试的需求。
- 如果你一定要换MySQL也完全不会影响生产库数据:只需要单独创建一个测试专用的MySQL库,在项目根目录的
.env.testing文件中配置对应的测试库连接信息,Laravel运行测试时会优先读取该文件的配置,RefreshDatabasetrait只会清空当前配置的测试库数据,只要你不要把测试库的连接参数填成生产库的,就不会有任何风险。
具体修复方式(二选一即可)
方案1:使用模型工厂生成测试数据(推荐,适合功能测试场景)
如果getRandParticipant是读取本地数据库的参与者数据,你只需要先给Participant模型创建工厂,在测试执行前生成测试数据即可:
- 生成Participant工厂(如果已经有可以跳过)
php artisan make:factory ParticipantFactory
- 在工厂文件
database/factories/ParticipantFactory.php中定义字段假值 - 在测试方法开头添加生成测试数据的代码:
public function test_createParticipants() { // 预生成5条参与者测试数据 \App\Models\Participant::factory()->count(5)->create(); $participant = Helper::getRandParticipant(); $type_participant = Helper::getType(2); $token = Helper::chooseToken($type_participant); $response = $this->post('/api/participants/create', [ 'token' => Helper::renewToken($participant, $token), 'type_participant' => $type_participant, 'callback' => $this->faker->sentence(20), ]); $response->assertStatus(200); $this->assertTrue(count(Task::all()) > 1); }
方案2:Mock Helper类方法(推荐,适合单元测试隔离依赖场景)
如果你的Helper方法需要调用第三方服务,不想在测试中发起真实请求,可以直接Mock Helper类的返回值,不需要准备数据也不需要调用真实接口:
首先确认你的Helper类已经继承了Laravel的Facade基类,之后就可以在测试中直接Mock:
public function test_createParticipants() { // 模拟Helper各方法的返回值 \Helper::shouldReceive('getRandParticipant') ->once() ->andReturn((object)[ 'id' => 1, 'participant' => '测试参与者', // 补充其他业务需要的字段 ]); \Helper::shouldReceive('getType') ->with(2) ->once() ->andReturn(1); \Helper::shouldReceive('chooseToken') ->with(1) ->once() ->andReturn('fake_test_token'); \Helper::shouldReceive('renewToken') ->once() ->andReturn('valid_fake_token'); $response = $this->post('/api/participants/create', [ 'token' => 'valid_fake_token', 'type_participant' => 1, 'callback' => $this->faker->sentence(20), ]); $response->assertStatus(200); $this->assertTrue(count(Task::all()) > 1); }
内容的提问来源于stack exchange,提问作者Evgeniy
相关产品推荐
相关产品推荐

