PHP 怎么数据驱动测试

wen PHP项目 2

本文目录导读:

PHP 怎么数据驱动测试

  1. 使用 PHPUnit 的 Data Provider
  2. 从外部文件读取测试数据
  3. 使用数据集合(数组)驱动
  4. 使用命名空间或其他工具库
  5. 高级用法:生成器提供数据
  6. 测试数据组织最佳实践
  7. 最佳实践建议:

在 PHP 中进行数据驱动测试有多种方式,下面我来介绍几种主流的方法:

使用 PHPUnit 的 Data Provider

这是最常用的方式,通过 @dataProvider 注解提供测试数据:

<?php
use PHPUnit\Framework\TestCase;
class CalculatorTest extends TestCase
{
    /**
     * @dataProvider additionProvider
     */
    public function testAdd($a, $b, $expected)
    {
        $calculator = new Calculator();
        $this->assertEquals($expected, $calculator->add($a, $b));
    }
    public function additionProvider()
    {
        return [
            'case1: positive numbers' => [1, 2, 3],
            'case2: negative numbers' => [-1, -2, -3],
            'case3: zeros' => [0, 0, 0],
            'case4: mixed' => [5, -3, 2],
        ];
    }
}

从外部文件读取测试数据

CSV 文件

<?php
class UserServiceTest extends TestCase
{
    /**
     * @dataProvider csvUserProvider
     */
    public function testValidateUser($name, $age, $expected)
    {
        $service = new UserService();
        $this->assertEquals($expected, $service->validate($name, $age));
    }
    public function csvUserProvider()
    {
        $data = [];
        $file = fopen(__DIR__ . '/test_data/users.csv', 'r');
        while (($row = fgetcsv($file)) !== false) {
            $data[] = $row;
        }
        fclose($file);
        return $data;
    }
}

JSON 文件

<?php
class ProductTest extends TestCase
{
    /**
     * @dataProvider jsonProductProvider
     */
    public function testProductPrice($productData, $expectedPrice)
    {
        $product = new Product($productData);
        $this->assertEquals($expectedPrice, $product->getPrice());
    }
    public function jsonProductProvider()
    {
        $json = file_get_contents(__DIR__ . '/test_data/products.json');
        $data = json_decode($json, true);
        $result = [];
        foreach ($data as $case) {
            $result[$case['name']] = [$case['data'], $case['expected']];
        }
        return $result;
    }
}

使用数据集合(数组)驱动

<?php
class DatabaseTest extends TestCase
{
    private $connection;
    public function setUp(): void
    {
        // 数据库连接初始化
    }
    /**
     * @dataProvider databaseTestCases
     */
    public function testDatabaseOperations($sql, $params, $expectedResult)
    {
        $result = $this->connection->execute($sql, $params);
        $this->assertEquals($expectedResult, $result);
    }
    public function databaseTestCases()
    {
        // 测试数据可以从配置文件、数据库或硬编码获取
        return [
            'select user by id' => [
                'SELECT * FROM users WHERE id = ?',
                [1],
                ['id' => 1, 'name' => 'John']
            ],
            'select user by email' => [
                'SELECT * FROM users WHERE email = ?',
                ['john@example.com'],
                ['id' => 1, 'email' => 'john@example.com']
            ],
        ];
    }
}

使用命名空间或其他工具库

使用数组组合生成(多参数交叉测试)

<?php
class ValidationTest extends TestCase
{
    /**
     * @dataProvider validationDataProvider
     */
    public function testEmailValidation($email, $expected)
    {
        $validator = new EmailValidator();
        $this->assertEquals($expected, $validator->validate($email));
    }
    public function validationDataProvider()
    {
        // 定义多组测试数据
        $validEmails = ['test@example.com', 'user.name@domain.com'];
        $invalidEmails = ['invalid-email', 'test@', '@test.com'];
        $data = [];
        foreach ($validEmails as $email) {
            $data["Valid email: $email"] = [$email, true];
        }
        foreach ($invalidEmails as $email) {
            $data["Invalid email: $email"] = [$email, false];
        }
        return $data;
    }
}

高级用法:生成器提供数据

<?php
class ApiTest extends TestCase
{
    /**
     * @dataProvider apiDataProvider
     */
    public function testApiEndpoint($endpoint, $payload, $expectedStatus)
    {
        $client = new GuzzleHttp\Client();
        $response = $client->request('POST', $endpoint, ['json' => $payload]);
        $this->assertEquals($expectedStatus, $response->getStatusCode());
    }
    public function apiDataProvider()
    {
        // 使用生成器懒加载数据
        return (function () {
            $testCases = [
                ['/api/login', ['username' => 'admin', 'password' => '123456'], 200],
                ['/api/login', ['username' => 'test', 'password' => 'wrong'], 401],
                ['/api/register', ['username' => 'newuser', 'password' => 'test123'], 201],
            ];
            foreach ($testCases as $case) {
                yield $case;
            }
        })();
    }
}

测试数据组织最佳实践

<?php
class DataDrivenTestTest extends TestCase
{
    /**
     * 测试配置:使用 YAML 或数组配置
     */
    public function testConfigDriven()
    {
        $config = [
            'test1' => ['input' => 'value1', 'expected' => 'result1'],
            'test2' => ['input' => 'value2', 'expected' => 'result2'],
            // ...
        ];
        foreach ($config as $caseName => $testData) {
            $result = $this->process($testData['input']);
            $this->assertEquals($testData['expected'], $result, "Case: $caseName failed");
        }
    }
    private function process($input)
    {
        // 业务逻辑
        return $input . '_processed';
    }
}

最佳实践建议:

  1. 数据与测试逻辑分离:将测试数据放在外部文件中(JSON、CSV、YAML)
  2. 使用有意义的名称:为每个测试用例提供描述性名称
  3. 保持数据独立性:每个测试用例应该相互独立
  4. 注意性能:数据量大时考虑使用生成器
  5. 错误信息清晰:添加有意义的错误信息
<?php
// 最佳实践示例
class DataDrivenExampleTest extends TestCase
{
    /**
     * @dataProvider excellentDataProvider
     */
    public function testExample($caseName, $input, $expected)
    {
        $result = $this->processData($input);
        $this->assertEquals($expected, $result, "Case '$caseName' failed");
    }
    public function excellentDataProvider()
    {
        // 从 JSON 文件读取并附带描述
        $dataFile = __DIR__ . '/fixtures/test_cases.json';
        $cases = json_decode(file_get_contents($dataFile), true);
        $provider = [];
        foreach ($cases as $case) {
            $provider[$case['description']] = [
                $case['description'],
                $case['input'],
                $case['expected']
            ];
        }
        return $provider;
    }
}

数据驱动测试的核心思想是:将测试数据从测试逻辑中分离出来,这样可以更容易地增加、修改测试用例,而不需要修改测试代码本身。

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