c-malet/class-test

PHP类测试

4.0.0 2023-12-21 16:08 UTC

This package is auto-updated.

Last update: 2024-09-21 17:54:13 UTC


README

Current version Supported PHP version CI

PHP测试库,专注于测试类,通过Prophecy模拟所有构造函数参数。

主要目标是通过自动创建测试类实例的占位参数来加速类测试,并为每个测试检索一个全新的实例。特别适用于测试具有许多构造函数参数的对象,例如助手、日志记录器、服务、存储库等,这些对象您不希望执行。

此库基于PHP对象模拟框架Prophecy,需要了解如何使用它,在此了解更多信息

简单示例

class TestSomeClass extends ClassTestCase {
    public function getTestedClassName() {
        return SomeClass::class;
    }
    
    public function getTestedClassConstructorParameters() {
        return [
            SomeRepository::class,
            SomeService::class,
            Logger::class,
            DbInterface::class,
            'someString'
        ];
    }
    
    public function testSomething() {
        // Retrieve a new instance of SomeClass with dummy constructor parameters
        // that can handle any parameters and return null all the time
        $someClass = $this->getTestedClass();
        
        $result = $someClass->doSomething('someText', 3);
        $this->assert(...);
    }
}

安装

先决条件

需要PHP 8.1或更高版本和PHPUnit ^9.0 || ^10.0

Composer

运行以下Composer命令 composer require c-malet/class-test

使用方法

测试设置

按如下方式设置测试类

扩展ClassTestCase类(它扩展了PHPUnit TestCase)

class TestSomeClass extends ClassTestCase {}

实现定义测试类的两个必填方法

public function getTestedClassName() {
    return SomeClass::class; // or the fully qualified class name
}

public function getTestedClassConstructorParameters() {
    return [
        SomeClass::class,
        SomeInterface::class,
        
        // An object can be provided directly, it will be kept unchanged
        $someObject, 
        
        // If you want to provide several instances of the same class,
        // or if you want to force a key to retrieve mocks later on, 
        // simply specify a key
        'Logger1' => LoggerInterface::class, 
        'Logger2' => LoggerInterface::class,
        
        // string, integer, array, ... can still be used directly
        'someString',
        12345,
        
        // If a string would match a class name for instance, you can still
        // force it as a string parameter this way
        'SomeClass' => ClassTestCase::STRING_PARAMETER
    ]
}

测试

对于每个测试,都会创建一个新的测试类实例,并可以检索它

$someClass = $this->getTestedClass();

您可以在每个测试用例中覆盖getTestedClass方法,以便告知您的IDE $someClass的类类型

它返回测试类的“真实”实例,它不是模拟,并且该类的所有代码都将执行。

相反,提供的每个与可实例化类匹配的构造函数参数都将转换为Prophecy,这样它们将自动处理任何参数,并默认返回null。

这些Prophecy模拟可以在测试期间随时检索,您可以使用getMock方法像使用Prophecy一样做任何您想做的事情,允许您根据需要覆盖默认的占位符设置。

$this->getProphecy(SomeRepository::class)->someMethod()->shouldBeCalled(1);

模拟可以按类名或键名检索,如前面在“测试设置”部分中所述

如果您的IDE无法从类名解析方法并给出警告,您也可以这样获取ProphecyMethod对象

$this->getProphecyMethod(SomeRepository::class, 'someMethod')->shouldBeCalled(1);

如果您希望使用内部模拟容器模拟任何其他类,例如在测试方法中希望使用的模拟,您还可以创建可以像其他模拟一样检索的模拟和占位符,使用addNewMock或addNewDummy。

$this->addNewMock(SomeClassToMock::class);
$this->addNewDummy(SomeClassToDummy::class);
...
$this->getProphecyMock(SomeClassToMock::class)->myMethod()->willReturn(true);

完整示例

class TestPizzaCooker extends ClassTestCase {
    public function getTestedClassName() {
        return PizzaCooker::class;
    }
    
    public function getTestedClassConstructorParameters() {
        OvenInterface::class,
        IngredientPicker::class,
        PizzaFolder::class,
        TimerHelper::class
    }
    
    public function testPizzaShouldAlwaysBeBaked() {
        $pizzaCooker = $this->getTestedClass();
        $pizzaCooker->cookPizza('margerhita', 'XL')

        $this->getProphecy(OvenInterface::class)->bake()->shouldHaveBeenCalled(1);
    }
    
    public function testPizzaCalzoneShouldBeFolded() {
        $pizza = $this->getProphecy(OvenInterface::class)->bake()->willReturn(
            $this->addNewDummy(Pizza::class)->reveal()
        );

        // Folder should fold the previously baked pizza 
        $this->getProphecyMethod(FolderInterface::class, 'fold')->with([$pizza->reveal()]);

        $pizzaCooker = $this->getTestedClass();
        $pizzaCooker->cookPizza('calzone')
        
        // A calzone should always be folded
        $this->getProphecy(FolderInterface::class)->bake()->shouldHaveBeenCalled(1);
    }
}

贡献

请参阅CONTRIBUTING文件。

安装/更新项目

您可以使用以下命令安装项目

make install

并使用以下命令更新

make update

注意:对于组件,composer.lock文件没有提交。

测试和CI(持续集成)

测试

您可以使用以下命令在您的侧边运行单元测试(带有覆盖率)

make tests

对于更美观的输出(但没有覆盖率),您可以使用以下命令

make testdox # run tests without coverage reports but with prettified output

代码风格

您也可以使用以下命令运行代码风格检查

make phpcs-check

您也可以使用以下命令运行代码风格修正

make phpcs-fix

静态分析

要执行您的代码的静态分析(使用phpstan,默认级别为9),可以使用以下命令

make phpstan

为确保您的代码与Deezer当前支持版本以及未来版本的PHP兼容,您需要运行以下命令(两者均需运行以实现完全支持)

最低支持版本

make php81compatibility

最高支持版本

make php83compatibility

CI模拟

最后,“辅助”命令,您可以在提交和推送之前运行

make ci