Skip to content

Instantly share code, notes, and snippets.

@blue7wings
Last active April 10, 2025 06:05
Show Gist options
  • Save blue7wings/4956246e16e219ef794763d6c55abffc to your computer and use it in GitHub Desktop.
Save blue7wings/4956246e16e219ef794763d6c55abffc to your computer and use it in GitHub Desktop.
Hyperf Unit Test Code Basic

单元测试编写规则

请严格遵守以下单元测试的规则:

  1. 单元测试为单个函数测试,不是集成测试,所以如果当前被测函数依赖其他服务,或者依赖Model层,则需要对其使用替身,以避免其他服务对当前测试的影响。
  2. 单元测试要尽量覆盖所有逻辑分支,包括正常分支和异常分支。
  3. 给每个单元测试增加注释,说明测试的场景和预期结果。

替身使用

如何给Model层编写替身

首先增加model替身,例如:mockAModel和mockBModel

<?php 

    use App\Model\AModel;
    use App\Model\BModel;


    protected function setUp(): void
    {
        parent::setUp();
        
        $this->mockAModel = Mockery::mock('overload:' . AModel::class);
        $this->mockBModel = Mockery::mock('overload:' . BModel::class);
    }

如果我们在 Service 代码中存在如下使用 Model 的代码:

AModel::query()
    ->whereBetween('log_date', [$yesterday, $today])
    ->where('locale', $this->localeName)
    ->select('product_id', 'product_price', 'log_date')
    ->get();

则我们需要在 Test 中如下对Model链式操作进行Mock

$mockAModelList = Collection::make([
    [
        'product_id'    => 1,
        'log_date'      => '2024-01-01',
        'locale'        => 'us',
        'product_price' => 100,
    ]
]);

$this->mockAModel
    ->shouldReceive('query->whereBetween->where->select->get')
    ->andReturn($mockAModelList);

如何给Service编写替身

如果我们当前Service也依赖其他Service,那么我还需要对其他Service进行Mock。比如,当前 CurrentService 依赖 OtherService,那么我需要如下进行Mock:

// CurrentService.php
class CurrentService {
    #[Inject]
    public OtherService $otherService;
}

// OtherService.php
class OtherService {
    public function aMethod() {
        return [];
    }
}

首先定义替身Service

    protected $currentService;
    protected $mockOtherService;

    protected function setUp(): void
    {
        parent::setUp();
        $this->currentService->otherService = Mockery::mock(OtherService::class);
    }

如果我们在CurrenctService函数中使用到OtherService的aMethod方法,那么我们就需要如下进行mock 那么我们就需要如下进行mock

    $this->currentService->otherService
        ->shouldReceive('aMethod')
        ->with(Mockery::any())
        ->andReturn([]);

如何运行单元测试

composer run test -- test/Cases/FoobarTest.php --filter "testBar"

其中FoobarTest.php是测试文件,而testBar是需要运行的单元测试,如果不指定单元测试,则运行整个文件

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment