symfonyboot/inject-mocks

此软件包已被废弃,不再维护。作者建议使用 https://github.com/silasyudi/inject-mocks 软件包。

通过 #InjectMocks 和 #Mock 注解自动将模拟对象注入测试主题,以加快 PHPUnit 的单元测试。

v3.0.0 2024-06-20 14:29 UTC

This package is auto-updated.

Last update: 2024-06-20 14:30:23 UTC


README

Inject-Mocks

Tests Maintainability Test Coverage

通过 #InjectMocks 和 #Mock 注解自动将模拟对象注入测试主题,以加快 PHPUnit 的单元测试。

摘要

语言 / Idioma

阅读葡萄牙语版本 🇧🇷 这里

安装

在开发环境中安装

composer require --dev silasyudi/inject-mocks

需求

  • PHP 8.3+
  • Composer 2

特性

在测试类中使用 #InjectMocks 和 #Mock 注解,可以自动将模拟对象注入测试主题。

在典型场景中,我们可能会这样做

没有 #InjectMocks/#Mock 的示例

class SomeTest extends \PHPUnit\Framework\TestCase
{
    public void testSomething() 
    {
        $someDependency = $this->createMock(Dependency::class);    
        $anotherDependency = $this->createMock(AnotherDependency::class);
        ...
        $subject = new Service($someDependency, $anotherDependency, ...);
        ...    
    }
    
    ...

这种方法会带来维护困难,因为如果测试主题发生变化,无论是添加、减少还是替换依赖项,都必须在每次测试中更改它。

有了 #InjectMocks/#Mock 注解,我们抽象化了这些测试主题的变化。示例

带有 #InjectMocks/#Mock 的示例

use SilasYudi\InjectMocks\InjectMocks;
use SilasYudi\InjectMocks\Mock;
use SilasYudi\InjectMocks\MockInjector;

class SomeTest extends \PHPUnit\Framework\TestCase
{
    #[Mock]
    private Dependency $someDependency;
    #[Mock]
    private AnotherDependency $anotherDependency;
    
    ...
    
    #[InjectMocks]
    
    public function setUp() : void 
    {
        MockInjector::inject($this);
    }
    
    public void testSomething()
    {
        // $this->subject e as dependências já estão instanciadas.
    }
    
    ...

用法

如前一个主题中的示例所示,#InjectMocks 属性必须放置在想要测试的测试主题属性上,而 #Mock 属性必须放置在想要模拟或注入的对应依赖项的属性上。

然后,使用句子 MockInjector::inject($this) 运行注入服务。这个执行可以在每个测试中或 setUp 中声明。

执行注入后,标记为 #InjectMocks 的 service 将是一个在测试类作用域中可用的真实实例,而标记为 #Mock 的每个依赖项都将是一个 MockObject 实例,通过构造函数注入到测试主题中,并且也将可在测试类作用域中使用。

详细信息

1. 属性范围

  • #InjectMocks 和 #Mock 必须放置在 TestCase 类中类型的属性上;
  • 接收 #InjectMocks 和 #Mock 属性的属性必须是对象;
  • 每个 TestCase 只能使用一个 #InjectMocks 属性。当在相同的作用域中使用多个时,此库将仅使用第一个,并忽略其他属性;
  • 您必须为每个要模拟的测试主题依赖项使用一个 #Mock 属性;
  • 在未类型化的属性或原始数据类型上使用属性将导致 MockInjectException 异常。
  • 当在同一测试类中使用相同类型的多个对象时,此库将通过属性名称进行匹配,这些名称必须与测试主题类相同。

2. 行为

#InjectMocks 和 #Mock 可以独立使用,也可以一起使用。每个的详细信息

2.1. #InjectMocks

它将通过构造函数创建一个真实实例,如果构造函数中有参数,将按以下顺序使用以下值

  • 从 #[Mock] 属性创建的 mock,如果存在的话;
  • 如果是可选参数,则使用 default 值;
  • 如果它被标记为 null,则使用 null
  • 如果它不是原始数据类型,则创建一个 mock。在这种情况下,此 mock 不会注入到 TestCase 作用域中;
  • 如果前面的选项不满足,则将抛出 MockInjectException 异常。

注意:您可以在测试主题的所有、一些或没有依赖项上使用 #Mock 属性。

2.2. #Mock

将在TestCase作用域中创建一个mock,而不使用构造函数。这种创建行为与TestCase::createMock()相同。