浅谈自动化测试 | 初遇自动化测试

Posted 测试萌萌

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈自动化测试 | 初遇自动化测试相关的知识,希望对你有一定的参考价值。

浅谈自动化测试

自动化测试(Test automation)是近年来逐渐兴起的软件开发流程,本系列文章将藉由作者过去的开发经验,与大家分享php/Laravel结合自动化测试的理论与实务,希望能对初学PHPUnit及自动化测试的同学有所帮助。

初遇自动化测试

在数年前,我刚从第一份工作离职,转职到第二份工作,新工作是在一个大集团的IT部门,职位是后端工程师。当时集团正准备导入一个由子公司开发的微服务系统,使用的技术是PHP 8及Laravel 9因为该系统在子公司运作得不错,因此集团高层想将它扩展成,全集团都可使用的规模,也因此需要招募人手来协助进行(而那个人手就是我)。

到职当天,部门副理协助我建置好环境,并告诉我子公司工程师在开发此微服务系统时,有写过很多自动化测试,建议我可以由阅读自动化测试案例,来了解这个微服务系统的功能。

这就是我第一接触到自动化测试,以及PHPUnit这个工具。

什么是自动化测试?

让我们来看看维基百科的定义:

In software testing, test automation is the use of software separate from the software being tested to control the execution of tests and the comparison of actual outcomes with predicted outcomes.

在软件测试中,测试自动化是指使用独立于被测软件的软件来控制测试的执行,以及实际结果与预测结果的比较。

换言之,所谓自动化测试 ,指的是使用其他软件来自动测试待测软件、比较实际结果与预期结果之异同、生成测试报告的这一个过程。

简单地说,就是用测试程序来测试原始程序的逻辑,是否符合预期。

为什么要写自动化测试?

这时候一定会有人问,手动测试不香吗,为什么要用自动化测试?多花时间写测试值得吗?

的确,大多数自动化测试能做到的事情,手动测试都能做到,且撰写自动化测试不是毫无成本,有时甚至会花上比开发功能本身,更多的人力成本来撰写测试。

但若我们从另一个角度来探讨,自动化测试基本上只有第一次撰写时最花时间,后续执行测试时,都是以秒来计算而且是让计算机自动执行测试程序来进行测试,只要测试脚本没问题,那计算机就会以正确的方式进行测试。

反观手动测试,因为执行测试的是人,而只要有人介入,就有一定的人为出错率,有可能是测试时漏了某个动作,导致测试要重来;有可能是漏了某个测试资料,导致测试又要重来;有可能是漏了某项测试案例,导致发生了改A坏B,上线了才爆炸;有可能测试者心情不好,没有心力按下测试键。

以上种种,都是人为手动测试可能发生的情况,若是使用自动化测试,这些情况大多可避免。

此外,手动测试花的是人力,通常以分钟来计算,这也是不小的成本。而自动化测试,会花到的成本大概只有几秒钟的电力。

自动化测试的优点与缺点

让我们来总结一下自动化测试的优缺点:

优点:

交给计算机来执行测试程序,执行测试时无需消耗人力,也可以避免人为因素导致的出错可以计算测试覆盖率,了解程序库中有多少被测试到。

缺点:

  • 需要花费额外成本开发测试程序

  • 需要花费额外成本建立测试环境

TDD与自动化测试的关联

许多人常会将自动化测试与近年流行的测试驱动开发(TDD, Test-Driven Development)挂勾在一起,但我认为实际上两者是描述不同的概念。

  • 自动化测试,指的是一种测试软件的测试方式;

  • 测试驱动开发,指的是一种先拟好测试,再撰写程序逻辑的,开发流程。

使用自动化测试,未必也采用了测试驱动开发,反之亦然。

举例来说,小A是一个API开发者,每当他在开发API时,他会先撰写程序逻辑,接着进行手动测试验证,确认无误后,再撰写自动化测试程序。

而另一位API开发者小B,他会先在纸上拟好各功能的测试案例,包含测试资料准备、测试流程、预期结果等,接着用这些案例测试程序。

因为对应的程序逻辑根本尚未开发,因此一定都不符测试预期,这时小B再开始开发各功能的程序逻辑,并在每次开发完一项功能时,就执行该功能相关的各测试案例,直到所有测试案例都被满足的当下,即为开发完成。

  • 在小A的例子中,他采用了自动化测试来测试程序,但没有使用测试驱动开发;

  • 在小B的例子中,他采用了测试驱动开发的开发流程,但没有使用自动化测试。

环境建置

下载与设定 Laradock

首先,让我们在Home资料夹下,将 Laradock 下载下来:

cd ~ && git clone https://github.com/Laradock/laradock.git Laradock

将 Laradock 下载回来后,切换到 Laradock 资料夹下,从样板复制一份 .env 档:

cd ~/Laradock
cp .env.example .env

接着开启 .env 档,有几个Key值需要关注:

1.APP_CODE_PATH_HOST:项目资料夹,指向我们的项目目录,这里输入 ../PHPUnit-test(稍候将在这个地方建立 Laravel 项目)

# Point to the path of your applications code on your hostAPP_CODE_PATH_HOST=../PHPUnit-test

2.DATA_PATH_HOST:资料路径,当 Laradock的数据库容器启动时,会在这个资料夹下建立相关档案及资料夹,预设值是 ~/.laradock/data,基本上保持预设值即可。

# Choose storage path on your machine. For all storage systemsDATA_PATH_HOST=~/.laradock/data

虽然乍看之下,此预设值会在Home资料夹下建立 .laradock 资料夹,但我实际测试时发现,Laradock 会在其所在资料夹下,建立一个名为 ~ 的资料夹,或许是一个神奇的Bug?

3.PHP_VERSION:PHP版本号,预设为 8.0 ,这里我们保持预设值

### PHP Version ############################################ Select a PHP version of the Workspace and PHP-FPM containers (Does not apply to HHVM).# Accepted values: 8.0 - 7.4 - 7.3 - 7.2 - 7.1 - 7.0 - 5.6PHP_VERSION=8.0

启动Laradock Workspace容器

在 ~/Laradock 目录下,输入以下指令,启动 workspace 容器:

#~/Laradockdocker-compose up -d workspace

workspace 容器是 Laradock 的一个核心容器,可以在这里执行 composer,之后我们也将在这个容器内执行 PHPUnit。

在启动 workspace 容器的同时, 同时会建立在前面设定的 .env key值:APP_CODE_PATH_HOST 所指向的资料夹(如果原本就已存在,则不会建立)。

进入Workspace容器

启动 workspace 容器后,接着我们要进入此容器内进行后续动作。

刚启动的 workspace 容器,预设名称是 laradock-workspace-1 ,让我们进入此容器:

docker exec -it laradock-workspace-1 bash

如果执行以上指令时,找不到该容器,显示 Error: No such container: 时,可先用以下指令查询已启动的 Docker 容器:

docker ps -a

初始化 Laravel 项目资料夹

进入 workspace 容器后,接着让我们来初始化项目资料夹。(这里提醒一下,进入容器后,会看到目前所在位置是 /var/www ,对应到本机的路径就是 ~/PHPUnit-test ,也就是前面 APP_CODE_PATH_HOST 所指向的路径)

接着我们使用 composer 来初始化 Laravel 项目资料夹:

composer create-project laravel/laravel .

接着就会开始安装 Laravel 到 ~/PHPUnit-test 资料夹了,应该会到类似以下的画面:

在初始化 Laravel 项目时,会一并安装 PHPUnit ,让我们来测试一下:

./vendor/bin/phpunit

 到这里,我们就完成了环境建置。

第一个单元测试

环境建好之后,我们来写第一个单元测试!不过在那之前,先让我们了解单元测试的“3个A”。

单元测试3A

所谓的3A,是指以下三个英文单字:

  • Arrange:初始化工作,如准备假资料

  • Act:执行测试对象

  • Assert:验证结果

一个良好的单元测试案例,应该包含以上的结构,依序执行 Arrange → Act → Assert,并显示验证结果,这样就是一个完整的单元测试程序。

第一个测试

事不宜迟,马上来写测试!

在开始撰写第一个测试前,先让我们做一个待测对象,我们以一个计算BMI的函数为例。

在 app\\Services 资料夹下,建立 TestService.php:

<?phpnamespace App\\Services;class TestService    public function calculateBmi(float $height, float $weight): float
            if ($weight <= 0)             return 0.0;
                return $weight / ($height * $height);
    

接着马上建立测试,在workspace容器内,项目资料夹下执行以下指令,建立单元测试:

php artisan make:test TestServiceTest --unit

建立 TestServiceTest.php 后,让我们来撰写测试函数:

<?phpnamespace Tests\\Unit;use App\\Services\\TestService;use PHPUnit\\Framework\\TestCase;class TestServiceTest extends TestCase    /**
     * Test calculateBmi
     */
    public function testCalculateBmi()
            // Arrange
        // 初始化待测对象
        // 以及执行测试所需的资料
        $service = app(TestService::class);
        $height = 1.6;
        $weight = 64.0;        // Act
        // 执行欲测试的函数/代码区块/行为
        $actualBmi = $service->calculateBmi($height, $weight);        // Assert
        // 验证测试结果
        $expectedBmi = 25;        $this->assertEquals($actualBmi, $expectedBmi);
    

首先,先来解释各个区块代码逻辑:

// Arrange// 初始化待测对象// 以及执行测试所需的资料$service = app(TestService::class);
$height = 1.6;
$weight = 64.0;

先建立1个 TestService 的实例 $service ,并初始化稍候执行待测对象时,所需的资料。

// Act// 执行欲测试的函数/代码区块/行为$actualBmi = $service->calculateBmi($height, $weight);

这就是执行要测试的代码区块。

// Assert
  // 验证测试结果
  $expectedBmi = 25;  $this->assertEquals($actualBmi, $expectedBmi);

进行验证,其中 $this→assertEquals 是目前我们所用到的第一个Assert函数,它用来验证第一个输入值(实际值)是否与第二个(期望值)输入值相等。

待测对象与测试案例都准备好后,就让我们来执行测试吧:

./vendor/bin/phpunit

应该会看到以下输出结果:

恭喜完成第一个单元测试!是不是很简单呢?

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!

以上是关于浅谈自动化测试 | 初遇自动化测试的主要内容,如果未能解决你的问题,请参考以下文章

十年经验大牛浅谈自动化测试与测试用例的编写

十年经验大牛浅谈自动化测试与测试用例的编写

浅谈自动化测试之持续集成

浅谈软件测试之回归测试

浅谈自动化测试 | 有关Assertion的这些函数,你了解吗?

Unity游戏开发浅谈Unity游戏开发中的单元测试