0

0

从 PHPUnit 到 Go:Go 开发人员的数据驱动单元测试

碧海醫心

碧海醫心

发布时间:2024-11-11 08:48:11

|

661人浏览过

|

来源于dev.to

转载

从 phpunit 到 go:go 开发人员的数据驱动单元测试

在这篇文章中,我们将探讨如何将 php 单元测试思维,特别是 phpunit 框架的数据提供者方法引入 go。如果您是一位经验丰富的 php 开发人员,您可能熟悉数据提供程序模型:在原始数组中单独收集测试数据并将这些数据输入到测试函数中。这种方法使单元测试更干净、更易于维护,并遵守开放/封闭等原则。

为什么采用数据提供者方法?

使用数据提供者方法在 go 中构建单元测试具有多种优势,包括:

增强的可读性和可扩展性:测试变得可视化组织,顶部有清晰分隔的数组代表每个测试场景。每个数组的键描述场景,而其内容保存测试该场景的数据。这种结构使文件易于处理并且易于扩展。

关注点分离:数据提供者模型将数据和测试逻辑分开,从而产生一个轻量级、解耦的函数,随着时间的推移,该函数可以基本保持不变。添加新场景只需要向提供者追加更多数据,保持测试功能对扩展开放,对修改关闭——开放/封闭原则在测试中的实际应用。

立即学习PHP免费学习笔记(深入)”;

在某些项目中,我什至看到了足够密集的场景,足以保证使用单独的 json 文件作为数据源,手动构建并提供给提供程序,而提供程序又向测试函数提供数据。

什么时候非常鼓励使用数据提供者?

当您有大量具有不同数据的测试用例时,特别鼓励使用数据提供程序:每个测试用例在概念上相似,但仅在输入和预期输出方面有所不同。

在单个测试函数中混合数据和逻辑会降低开发人员体验 (dx)。它通常会导致:

冗长过载:重复具有轻微数据变化的语句的冗余代码,导致代码库冗长而没有额外的好处。

清晰度降低:当尝试将实际测试数据与周围代码隔离时,扫描测试函数变得很麻烦,而数据提供程序方法自然可以缓解这种情况。

很好,那么数据提供者到底是什么?

phpunit 中的 dataprovider 模式,基本上提供程序函数为测试函数提供在隐式循环中使用的不同数据集。它确保了 dry(不要重复自己)原则,并与开放/封闭原则保持一致,使得在不改变核心测试功能逻辑的情况下更容易添加或修改测试场景。

在没有数据提供者的情况下解决问题?

为了说明冗长、代码重复和维护挑战的缺点,下面是在没有数据提供者帮助的情况下对冒泡排序函数进行单元测试的示例片段:

assertsame([], bubblesort([]));
    }

    public function testbubblesortoneelement()
    {
        $this->assertsame([0], bubblesort([0]));
    }

    public function testbubblesorttwoelementssorted()
    {
        $this->assertsame([5, 144], bubblesort([5, 144]));
    }

    public function testbubblesorttwoelementsunsorted()
    {
        $this->assertsame([-7, 10], bubblesort([10, -7]));
    }

    public function testbubblesortmultipleelements()
    {
        $this->assertsame([1, 2, 3, 4], bubblesort([1, 3, 4, 2]));
    }

    // and so on for each test case, could be 30 cases for example.

    public function testbubblesortdescendingorder()
    {
        $this->assertsame([1, 2, 3, 4, 5], bubblesort([5, 4, 3, 2, 1]));
    }

    public function testbubblesortboundaryvalues()
    {
        $this->assertsame([-2147483647, 2147483648], bubblesort([2147483648, -2147483647]));
    }
}

上面的代码有问题吗?当然:

Audo Studio
Audo Studio

AI音频清洗工具(噪音消除、声音平衡、音量调节)

下载

冗长:每个测试用例都需要一个单独的方法,从而导致大量重复的代码库。

重复:测试逻辑在每个方法中重复,仅根据输入和预期输出而变化。

开放/封闭违规:添加新的测试用例需要通过创建更多方法来改变测试类结构。

解决数据提供者的问题!

这是使用数据提供者重构的相同测试套件


     */
    public function bubblesortdataprovider(): array
    {
        return [
            'empty' => [[], []],
            'oneelement' => [[0], [0]],
            'twoelementssorted' => [[5, 144], [5, 144]],
            'twoelementsunsorted' => [[10, -7], [-7, 10]],
            'morethanoneelement' => [[1, 3, 4, 2], [1, 2, 3, 4]],
            'morethanoneelementwithrepetition' => [[1, 4, 4, 2], [1, 2, 4, 4]],
            'morethanoneelement2' => [[7, 7, 1, 0, 99, -5, 10], [-5, 0, 1, 7, 7, 10, 99]],
            'sameelement' => [[1, 1, 1, 1], [1, 1, 1, 1]],
            'negativenumbers' => [[-5, -2, -10, -1, -3], [-10, -5, -3, -2, -1]],
            'descendingorder' => [[5, 4, 3, 2, 1], [1, 2, 3, 4, 5]],
            'randomorder' => [[9, 2, 7, 4, 1, 6, 3, 8, 5], [1, 2, 3, 4, 5, 6, 7, 8, 9]],
            'duplicateelements' => [[2, 2, 1, 1, 3, 3, 4, 4], [1, 1, 2, 2, 3, 3, 4, 4]],
            'largearray' => [[-1, -10000, -12345, -2032, -23, 0, 0, 0, 0, 10, 10000, 1024, 1024354, 155, 174, 1955, 2, 255, 3, 322, 4741, 96524], [-1, -10000, -12345, -2032, -23, 0, 0, 0, 0, 10, 10000, 1024, 1024354, 155, 174, 1955, 2, 255, 3, 322, 4741, 96524]],
            'singlenegativeelement' => [[-7], [-7]],
            'arraywithzeroes' => [[0, -2, 0, 3, 0], [-2, 0, 0, 0, 3]],
            'ascendingorder' => [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5]],
            'descendingorderwithduplicates' => [[5, 5, 4, 3, 3, 2, 1], [1, 2, 3, 3, 4, 5, 5]],
            'boundaryvalues' => [[2147483648, -2147483647], [-2147483647, 2147483648]],
            'mixedsignnumbers' => [[-1, 0, 1, -2, 2], [-2, -1, 0, 1, 2]],
        ];
    }

    /**
     * @dataprovider bubblesortdataprovider
     *
     * @param array $input
     * @param array $expected
     */
    public function testbubblesort(array $input, array $expected)
    {
        $this->assertsame($expected, bubblesort($input));
    }
}

使用数据提供者有什么优势吗?哦,是的:

简洁:所有测试数据都集中在一个方法中,无需针对每个场景使用多个函数。

增强可读性:每个测试用例都组织良好,每个场景都有描述性的键。

开放/封闭原则:可以在不改变核心测试逻辑的情况下向数据提供者添加新案例。

改进的 dx(开发人员体验):测试结构干净、吸引人,甚至让那些懒惰的开发人员也有动力去扩展、调试或更新它。

让数据提供商走上正轨

  • go 没有像 phpunit 这样的原生数据提供者模型,因此我们需要使用不同的方法。可能有多种复杂程度的实现,以下是一个平均的实现,可能是在 go 中模拟数据提供者的候选者
package sort

import (
    "testing"

    "github.com/stretchr/testify/assert"
)

type TestData struct {
    ArrayList    map[string][]int
    ExpectedList map[string][]int
}

const (
    maxInt32 = int32(^uint32(0) >> 1)
    minInt32 = -maxInt32 - 1
)

var testData = &TestData{
    ArrayList: map[string][]int{
        "empty":                            {},
        "oneElement":                       {0},
        "twoElementsSorted":                {5, 144},
        "twoElementsUnsorted":              {10, -7},
        "moreThanOneElement":               {1, 3, 4, 2},
        "moreThanOneElementWithRepetition": {1, 4, 4, 2},
        "moreThanOneElement2":              {7, 7, 1, 0, 99, -5, 10},
        "sameElement":                      {1, 1, 1, 1},
        "negativeNumbers":                  {-5, -2, -10, -1, -3},
        "descendingOrder":                  {5, 4, 3, 2, 1},
        "randomOrder":                      {9, 2, 7, 4, 1, 6, 3, 8, 5},
        "duplicateElements":                {2, 2, 1, 1, 3, 3, 4, 4},
        "largeArray":                       {-1, -10000, -12345, -2032, -23, 0, 0, 0, 0, 10, 10000, 1024, 1024354, 155, 174, 1955, 2, 255, 3, 322, 4741, 96524},
        "singleNegativeElement":            {-7},
        "arrayWithZeroes":                  {0, -2, 0, 3, 0},
        "ascendingOrder":                   {1, 2, 3, 4, 5},
        "descendingOrderWithDuplicates":    {5, 5, 4, 3, 3, 2, 1},
        "boundaryValues":                   {2147483648, -2147483647},
        "mixedSignNumbers":                 {-1, 0, 1, -2, 2},
    },
    ExpectedList: map[string][]int{
        "empty":                            {},
        "oneElement":                       {0},
        "twoElementsSorted":                {5, 144},
        "twoElementsUnsorted":              {-7, 10},
        "moreThanOneElement":               {1, 2, 3, 4},
        "moreThanOneElementWithRepetition": {1, 2, 4, 4},
        "moreThanOneElement2":              {-5, 0, 1, 7, 7, 10, 99},
        "sameElement":                      {1, 1, 1, 1},
        "negativeNumbers":                  {-10, -5, -3, -2, -1},
        "descendingOrder":                  {1, 2, 3, 4, 5},
        "randomOrder":                      {1, 2, 3, 4, 5, 6, 7, 8, 9},
        "duplicateElements":                {1, 1, 2, 2, 3, 3, 4, 4},
        "largeArray":                       {-1, -10000, -12345, -2032, -23, 0, 0, 0, 0, 10, 10000, 1024, 1024354, 155, 174, 1955, 2, 255, 3, 322, 4741, 96524},
        "singleNegativeElement":            {-7},
        "arrayWithZeroes":                  {-2, 0, 0, 0, 3},
        "ascendingOrder":                   {1, 2, 3, 4, 5},
        "descendingOrderWithDuplicates":    {1, 2, 3, 3, 4, 5, 5},
        "boundaryValues":                   {-2147483647, 2147483648},
        "mixedSignNumbers":                 {-2, -1, 0, 1, 2},
    },
}

func TestBubble(t *testing.T) {

    for testCase, array := range testData.ArrayList {
        t.Run(testCase, func(t *testing.T) {
            actual := Bubble(array)
            assert.ElementsMatch(t, actual, testData.ExpectedList[testCase])
        })

    }
}
  • 我们基本上定义了两个映射/列表:一个用于输入数据,第二个用于预期数据。我们确保双方的每个案例场景都通过双方相同的映射键进行引用。
  • 执行测试就是一个简单函数中的循环问题,该函数迭代准备好的输入/预期列表。
  • 除了一些一次性的样板类型之外,对测试的修改应该只发生在数据方面,大多数情况下不应该改变执行测试的函数的逻辑,从而实现我们上面谈到的目标:测试工作归结为原始数据准备问题。

奖励:可以在此处找到实现本博文中呈现的逻辑的 github 存储库 https://github.com/medunes/dsa-go。到目前为止,它包含运行这些测试的 github 操作,甚至显示超级著名的绿色徽章;)

下一篇[希望]信息丰富的帖子中见!

相关文章

驱动精灵
驱动精灵

驱动精灵基于驱动之家十余年的专业数据积累,驱动支持度高,已经为数亿用户解决了各种电脑驱动问题、系统故障,是目前有效的驱动软件,有需要的小伙伴快来保存下载体验吧!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
php文件怎么打开
php文件怎么打开

打开php文件步骤:1、选择文本编辑器;2、在选择的文本编辑器中,创建一个新的文件,并将其保存为.php文件;3、在创建的PHP文件中,编写PHP代码;4、要在本地计算机上运行PHP文件,需要设置一个服务器环境;5、安装服务器环境后,需要将PHP文件放入服务器目录中;6、一旦将PHP文件放入服务器目录中,就可以通过浏览器来运行它。

2787

2023.09.01

php怎么取出数组的前几个元素
php怎么取出数组的前几个元素

取出php数组的前几个元素的方法有使用array_slice()函数、使用array_splice()函数、使用循环遍历、使用array_slice()函数和array_values()函数等。本专题为大家提供php数组相关的文章、下载、课程内容,供大家免费下载体验。

1685

2023.10.11

php反序列化失败怎么办
php反序列化失败怎么办

php反序列化失败的解决办法检查序列化数据。检查类定义、检查错误日志、更新PHP版本和应用安全措施等。本专题为大家提供php反序列化相关的文章、下载、课程内容,供大家免费下载体验。

1546

2023.10.11

php怎么连接mssql数据库
php怎么连接mssql数据库

连接方法:1、通过mssql_系列函数;2、通过sqlsrv_系列函数;3、通过odbc方式连接;4、通过PDO方式;5、通过COM方式连接。想了解php怎么连接mssql数据库的详细内容,可以访问下面的文章。

1016

2023.10.23

php连接mssql数据库的方法
php连接mssql数据库的方法

php连接mssql数据库的方法有使用PHP的MSSQL扩展、使用PDO等。想了解更多php连接mssql数据库相关内容,可以阅读本专题下面的文章。

1464

2023.10.23

html怎么上传
html怎么上传

html通过使用HTML表单、JavaScript和PHP上传。更多关于html的问题详细请看本专题下面的文章。php中文网欢迎大家前来学习。

1255

2023.11.03

PHP出现乱码怎么解决
PHP出现乱码怎么解决

PHP出现乱码可以通过修改PHP文件头部的字符编码设置、检查PHP文件的编码格式、检查数据库连接设置和检查HTML页面的字符编码设置来解决。更多关于php乱码的问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

1569

2023.11.09

php文件怎么在手机上打开
php文件怎么在手机上打开

php文件在手机上打开需要在手机上搭建一个能够运行php的服务器环境,并将php文件上传到服务器上。再在手机上的浏览器中输入服务器的IP地址或域名,加上php文件的路径,即可打开php文件并查看其内容。更多关于php相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

1307

2023.11.13

菜鸟裹裹入口以及教程汇总
菜鸟裹裹入口以及教程汇总

本专题整合了菜鸟裹裹入口地址及教程分享,阅读专题下面的文章了解更多详细内容。

0

2026.01.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Git 教程
Git 教程

共21课时 | 2.9万人学习

Git版本控制工具
Git版本控制工具

共8课时 | 1.5万人学习

Git中文开发手册
Git中文开发手册

共0课时 | 0人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号