lucatume/codeception-snapshot-assertions

Codeception的快照断言糖语法。

1.2.0 2023-10-14 15:15 UTC

This package is auto-updated.

Last update: 2024-09-14 17:16:30 UTC


README

利用Codeception的快照支持,使Codeception项目中的快照测试更加容易。

代码示例

<?php
class WidgetTest extends Codeception\TestCase\Test
{
    use tad\Codeception\SnapshotAssertions\SnapshotAssertions;
    public function testDefaultContent(){
        $widget = new Widget() ;

        $this->assertMatchesHtmlSnapshot($widget->html());
    }
    
    public function testOutput(){
       $widget = new Widget(['title' => 'Test Widget', 'content' => 'Some test content']) ;

       $this->assertMatchesHtmlSnapshot($widget->html());
    }
}

需求

此包基于Codeception自2.5.0版本以来添加的快照支持,因此库的要求如下:

  • PHP 5.6+
  • Codeception 2.5+

安装

使用Composer安装此包

composer install lucatume/codeception-snapshot-assertions

Codeception是该包运行的要求之一,如果没有在项目的Composer配置文件(composer.json)中指定,它将被作为依赖项安装。

什么是快照测试?

快照测试是测试代码输出的便捷方式。
快照测试比完整的视觉端到端测试(但这不是替代品)更快,但比低级别的单元测试(同样不是替代品)更容易编写。
这种测试适合用于单元和集成测试来自动化输出测试。
关于快照测试的更多信息请在此处阅读

这与Codeception所做的有何不同?

  • 快照不需要编写专门的类,您只需在测试用例中use tad\Codeception\SnapshotAssertions\SnapshotAssertions trait并提供的一个assertMatches...方法即可。
  • 它也支持字符串和HTML快照测试。
  • 代码生成的快照存储在与它们相同的文件夹中,即生成的文件夹中的__snapshots__

这与Spatie包有何不同?

  • 它利用了Codeception自己的快照实现,因此它将不会在纯PhpUnit上工作
  • 它将库要求从PHP 7.0降低到PHP 5.6。

用法

该包支持以下类型的断言:

  1. 字符串快照断言,使用assertMatchesStringSnapshot方法将字符串与字符串快照进行比较。
  2. HTML快照断言,使用assertMatchesHtmlSnapshot方法将HTML片段与HTML片段快照进行比较。
  3. JSON快照断言,使用assertMatchesJsonSnapshot方法将JSON字符串与存储的JSON快照进行比较。
  4. 代码快照断言,使用assertMatchesCodeSnapshot方法将代码与存储的代码快照进行比较。

首次调用assert...方法时,库将在与测试相同的目录中生成一个快照文件,在__snapshots__文件夹中。
例如,如果以下测试用例位于tests/Output/WidgetTest.php文件中,那么当testDefaultContent方法运行时,库将生成tests/Output/WidgetTest__testDefaultContent__0.snapshot.html文件;您可以通过在调试模式下运行Codeception测试来重新生成失败的快照(使用run命令的--debug标志)。

配置

该库与Codeception配置系统集成,允许设置一些配置选项。

  • 该库支持两个配置参数:
  • version(字符串):将作为快照文件名的前缀;默认为空字符串(``)。

refresh(布尔值):在失败时自动强制重新生成快照;默认为false

# Codeception own configuration
paths:
  tests: tests
  output: tests/_output
  data: tests/_data
  support: tests/_support
  envs: tests/_envs
actor_suffix: Tester
extensions:
  enabled:
    - Codeception\Extension\RunFailed
# Snapshot configuration
snapshot:
  version: 23
  refresh: true

配置参数可以在codeception.ymlcodeception.dist.yml文件中的snapshot键下设置,如下所示

版本

<?php
use Codeception\Test\Unit;

class WidgetTest extends Unit {
  public function testDefaultContent():void {
    $widget = new Widget() ;
    $this->assertMatchesHtmlSnapshot($widget->html());
  }
}

如果将version字符串设置为非空值,则快照文件名将添加该前缀。在以下示例中,version参数设置为alt,快照文件名将为WidgetTest__alt__testDefaultContent__alt.snapshot.html

如果未设置version参数,或设置为空字符串,则快照文件名将不添加任何前缀,并将为WidgetTest__testDefaultContent__0.snapshot.html

刷新

如果将refresh参数设置为true,则在失败时将自动重新生成快照。通常,Codeception快照通过在调试模式下运行测试(使用run命令的--debug标志)并回复提示是否重新生成快照;或者手动删除快照文件来重新生成。如果将refresh参数设置为true,则在失败时将自动重新生成快照,无需提示,如果当前测试运行在调试模式下。

字符串断言
当方法输出为纯文本字符串时,此类断言很有用。
此类断言产生的快照将具有.snapshot.txt文件扩展名。
用于制作字符串快照断言的方法是tad\Codeception\SnapshotAssertions\SnapshotAssertions::assertStringSnapshot()

<?php
class ErrorMessageTest extends Codeception\TestCase\Test
{
    use tad\Codeception\SnapshotAssertions\SnapshotAssertions;
    
    public function testClassAndMethodOutput(){
        $errorMessage = new ErrorMessage(__CLASS__, 'foo') ;

        $this->assertMatchesStringSnapshot($errorMessage->message());
    }
    
    public function testClassOnlyOutput(){
        $errorMessage = new ErrorMessage(__CLASS__) ;

        $this->assertMatchesStringSnapshot($errorMessage->message());
    }
}

使用示例

HTML断言
当方法输出为HTML文档或HTML片段时,此类断言很有用。
此类断言产生的快照将具有.snapshot.html文件扩展名。
用于制作字符串快照断言的方法是tad\Codeception\SnapshotAssertions\SnapshotAssertions::assertStringSnapshot()

<?php
class WidgetTest extends Codeception\TestCase\Test
{
    use tad\Codeception\SnapshotAssertions\SnapshotAssertions;
    
    public function testDefaultContent(){
        $widget = new Widget() ;

        $this->assertMatchesHtmlSnapshot($widget->html());
    }
    
    public function testOutput(){
       $widget = new Widget(['title' => 'Test Widget', 'content' => 'Some test content']) ;

       $this->assertMatchesHtmlSnapshot($widget->html());
    }
}

用于制作HTML快照断言的方法是tad\Codeception\SnapshotAssertions\SnapshotAssertions::assertHtmlSnapshot()

JSON断言
当方法输出为HTML文档或HTML片段时,此类断言很有用。
当方法输出为JSON字符串时,此类断言很有用。
用于制作JSON快照断言的方法是tad\Codeception\SnapshotAssertions\SnapshotAssertions::assertJsonSnapshot()

<?php
class ApiTest extends Codeception\TestCase\Test
{
    use tad\Codeception\SnapshotAssertions\SnapshotAssertions;
    
    public function testGoodResponse(){
        $this->givenTheUserIsAuthenticated();
        $request = new Request([
            'me' => [
                'name'   
            ]
        ]);
        
        $api = new API() ;

        $this->assertMatchesJsonSnapshot($api->handle($request));
    }

    public function testMissingAuthResponse(){
        $request = new Request([
            'me' => [
                'name'   
            ]
        ]);
        
        $api = new API() ;

        $this->assertMatchesJsonSnapshot($api->handle($request));
    }
}

使用示例

代码断言
当方法输出为代码时,此类断言很有用。
此类断言产生的快照将默认具有.snapshot.php文件扩展名,但您可以指定用于快照的扩展名。
用于制作字符串快照断言的方法是tad\Codeception\SnapshotAssertions\SnapshotAssertions::assertStringSnapshot()

<?php
class ApiTest extends Codeception\TestCase\Test
{
    use tad\Codeception\SnapshotAssertions\SnapshotAssertions;
    
    public function testGoodCode(){
		$generator = new CodeGenerator();
		$code = $generator->produce('phpCode');
        $this->assertMatchesCodeSnapshot($code);
    }

    public function testMissingAuthResponse(){
		$generator = new CodeGenerator();
		$code = $generator->produce('jsCode');
        $this->assertMatchesCodeSnapshot($code);
    }
}

用于制作代码快照断言的方法是tad\Codeception\SnapshotAssertions\SnapshotAssertions::assertCodeSnapshot()

目录断言
当代码块输出为目录及其文件时,此类断言很有用,以确保目录结构和内容在一段时间内不发生变化。
此断言将检查当前目录和快照中捕获的目录具有相同的文件,以及每个文件的内容相同。
此类断言产生的快照将具有.snapshot文件扩展名;它们是纯文本文件。
用于制作字符串快照断言的方法是tad\Codeception\SnapshotAssertions\SnapshotAssertions::assertStringSnapshot()

<?php
class DirectorySetupTest extends Codeception\TestCase\Test
{
    use tad\Codeception\SnapshotAssertions\SnapshotAssertions;
    
    public function testGoodDirectorySetUp(){
		$generator = new DirectorySetup();
        $destination = codecept_output_dir('test');

		$generator->setUpDirectory('test', $destination );

        $this->assertMatchesDirectorySnapshot($destination);
    }

    public function testFailingDirectorySetUp(){
		$generator = new DirectorySetup();
        $destination = codecept_output_dir('failing');

		$generator->setUpDirectory('failing', $destination );

        $this->assertMatchesDirectorySnapshot($destination);
    }
}

用于制作代码快照断言的方法是tad\Codeception\SnapshotAssertions\SnapshotAssertions::assertDirectorySnapshot()

访问者函数

为了允许更精细地控制对数据进行的断言方式,每个快照实现都支持“数据访问者”。
数据访问者是一个callable,它将从快照实现接收预期数据和当前数据。

根据快照类型,回调接收到的参数可能不同或超过两个。

在以下示例中,数据访客被用来从目录快照中排除一些文件,并从某些文件中丢弃一些散列行

<?php

public function test_files(){
        $dataVisitor = static function ($expected, $current, $pathName) {
            if (strpos($pathName, 'fileOne')) {
                // Empty file one, like dropping it.
                return [[], []];
            }

            if (strpos($pathName, 'fileTwo')) { 
                // Remove the hash line in file two.
                $removeHashLine = static function ($line) {
                    return !preg_match('/\\/\\/\\s*\\[HASH].*$/uim', $line);
                };
                return [
                    array_filter($expected, $removeHashLine),
                    array_filter($current, $removeHashLine)
                ];
            }

            return [$expected, $current];
        };
    
        $dirToTest = codecept_output('dir-to-test');
        $snapshot =  new DirectorySnapshot($dirToTest);
        $snapshot->setDataVisitor($dataVisitor);
        $snapshot->assert();
}

在这个示例中,数据访客被用来从JSON对象中移除一些散列数据

<?php

public function test_json_object(){
        $removeHashEntry = static function ($jsonString) {
            // Remove the `hash` key from the JSON object.
            return json_encode(array_diff_key(json_decode($jsonString, true), array_flip(['hash'])));
        };
        $dataVisitor = static function ($expected, $current) use ($removeHashEntry) {
            return array_map($removeHashEntry, [$expected, $current]);
        };

        // This first snapshot will create the first HTML snapshot.
        $firstSnapshot = new JsonSnapshot(MyJsonProducingObject::data());
        $firstSnapshot->setDataVisitor($dataVisitor);
        $firstSnapshot->assert();
}