PHP 怎么模型测试

wen PHP项目 3

本文目录导读:

PHP 怎么模型测试

  1. 基础测试框架配置
  2. 模型单元测试示例
  3. 关系测试
  4. 使用工厂模式测试
  5. 数据验证测试
  6. 模拟外部依赖
  7. 性能测试
  8. 最佳实践建议
  9. 运行测试

在 PHP 中进行模型测试,通常涉及单元测试和集成测试,以下是系统性的测试方法:

基础测试框架配置

使用 PHPUnit

composer require --dev phpunit/phpunit

phpunit.xml 配置

<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true">
    <testsuites>
        <testsuite name="Model Test Suite">
            <directory>tests/Models</directory>
        </testsuite>
    </testsuites>
</phpunit>

模型单元测试示例

Laravel 模型测试

<?php
namespace Tests\Unit\Models;
use Tests\TestCase;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
class UserModelTest extends TestCase
{
    use RefreshDatabase;
    /** @test */
    public function user_can_be_created()
    {
        $user = User::create([
            'name' => 'John Doe',
            'email' => 'john@example.com',
            'password' => bcrypt('secret123')
        ]);
        $this->assertDatabaseHas('users', [
            'email' => 'john@example.com'
        ]);
        $this->assertInstanceOf(User::class, $user);
    }
    /** @test */
    public function user_has_correct_fillable_fields()
    {
        $user = new User();
        $this->assertEquals([
            'name',
            'email',
            'password',
        ], $user->getFillable());
    }
    /** @test */
    public function user_password_is_hashed()
    {
        $user = User::create([
            'name' => 'Jane Doe',
            'email' => 'jane@example.com',
            'password' => 'plain-password'
        ]);
        $this->assertNotEquals('plain-password', $user->password);
        $this->assertTrue(password_verify('plain-password', $user->password));
    }
}

纯 PHP 模型测试

<?php
namespace Tests\Unit;
use PHPUnit\Framework\TestCase;
use App\Models\Product;
class ProductModelTest extends TestCase
{
    /** @var Product */
    private $product;
    protected function setUp(): void
    {
        parent::setUp();
        $this->product = new Product();
    }
    /** @test */
    public function product_can_calculate_total_price()
    {
        $this->product->setPrice(100);
        $this->product->setQuantity(3);
        $this->assertEquals(300, $this->product->getTotalPrice());
    }
    /** @test */
    public function product_name_is_required()
    {
        $this->expectException(\InvalidArgumentException::class);
        $this->product->setName('');
    }
}

关系测试

测试关联关系

<?php
namespace Tests\Feature\Models;
use Tests\TestCase;
use App\Models\Order;
use App\Models\User;
use App\Models\OrderItem;
use Illuminate\Foundation\Testing\RefreshDatabase;
class OrderModelTest extends TestCase
{
    use RefreshDatabase;
    /** @test */
    public function order_belongs_to_user()
    {
        $user = User::factory()->create();
        $order = Order::factory()->create(['user_id' => $user->id]);
        $this->assertInstanceOf(User::class, $order->user);
        $this->assertEquals($user->id, $order->user->id);
    }
    /** @test */
    public function order_has_many_order_items()
    {
        $order = Order::factory()->create();
        OrderItem::factory()->count(3)->create(['order_id' => $order->id]);
        $this->assertCount(3, $order->orderItems);
        $this->assertInstanceOf(OrderItem::class, $order->orderItems->first());
    }
    /** @test */
    public function order_can_calculate_total()
    {
        $order = Order::factory()->create();
        OrderItem::factory()->create([
            'order_id' => $order->id,
            'price' => 100,
            'quantity' => 2
        ]);
        OrderItem::factory()->create([
            'order_id' => $order->id,
            'price' => 50,
            'quantity' => 1
        ]);
        $this->assertEquals(250, $order->calculateTotal());
    }
}

使用工厂模式测试

定义 Model Factory

<?php
namespace Database\Factories;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
class UserFactory extends Factory
{
    protected $model = User::class;
    public function definition()
    {
        return [
            'name' => $this->faker->name,
            'email' => $this->faker->unique()->safeEmail,
            'password' => bcrypt('password'),
        ];
    }
    public function admin()
    {
        return $this->state([
            'is_admin' => true,
        ]);
    }
}

使用工厂测试

/** @test */
public function admin_users_have_admin_privileges()
{
    $admin = User::factory()->admin()->create();
    $regularUser = User::factory()->create();
    $this->assertTrue($admin->isAdmin());
    $this->assertFalse($regularUser->isAdmin());
}

数据验证测试

/** @test */
public function model_validates_required_fields()
{
    $order = new Order(['user_id' => null]);
    $this->assertFalse($order->validate());
    $this->assertArrayHasKey('user_id', $order->errors());
}
/** @test */
public function model_validates_email_format()
{
    $user = new User(['email' => 'invalid-email']);
    $this->assertFalse($user->validate());
    $this->assertArrayHasKey('email', $user->errors());
}

模拟外部依赖

use Mockery;
/** @test */
public function model_calls_external_service()
{
    $externalService = Mockery::mock(ExternalService::class);
    $externalService->shouldReceive('sendEmail')
        ->once()
        ->andReturn(true);
    $user = new User();
    $user->setExternalService($externalService);
    $result = $user->sendWelcomeEmail();
    $this->assertTrue($result);
}

性能测试

/** @test */
public function model_query_uses_indexes()
{
    $queries = 0;
    DB::listen(function ($query) use (&$queries) {
        $queries++;
        // 检查查询是否使用索引
        $this->assertStringNotContainsString('TABLE SCAN', $query->sql);
    });
    // 执行查询
    User::where('email', 'john@example.com')->first();
    $this->assertLessThan(5, $queries);
}

最佳实践建议

测试层级划分:

  1. 单元测试 - 单个模型方法
  2. 集成测试 - 模型与数据库交互
  3. 特征测试 - 完整业务流

关键要点:

/** @test */
public function test_model_scope()
{
    // 测试查询作用域
    $activeUsers = User::active()->get();
    $this->assertNotEmpty($activeUsers);
}
/** @test */
public function test_model_accessors()
{
    $user = User::factory()->create([
        'first_name' => 'John',
        'last_name' => 'Doe'
    ]);
    $this->assertEquals('John Doe', $user->full_name);
}
/** @test */
public function test_model_mutators()
{
    $user = new User();
    $user->email = 'TEST@example.com';
    $this->assertEquals('test@example.com', $user->email);
}

运行测试

# 运行所有测试
php artisan test
# 运行特定测试文件
php artisan test --filter=UserModelTest
# 运行测试并生成覆盖率
php vendor/bin/phpunit --coverage-html coverage/

这样系统化的测试方法能确保你的 PHP 模型逻辑正确、可靠且可维护。

抱歉,评论功能暂时关闭!