作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
瓦西里·科瓦尔的头像

瓦西里•Koval

Vasily是一名拥有超过9年丰富开发经验的web开发人员, 优化, 支持web应用程序.

专业知识

工作经验

20

分享

在继续之前 Codeception 和PHP, 我们应该介绍基础知识,并首先解释为什么我们需要在应用程序中进行测试. 也许我们可以不把时间浪费在测试上而完成一个项目,至少这次是这样?

Sure, you don’t need 测试 for everything; for example, when you want to build yet another homepage. 当项目包含由一个路由器链接的静态页面时,可能不需要测试.

然而,在以下情况下,你确实需要测试:

  • 您的团队使用BDD/TDD.
  • 您的Git仓库包含多个提交.
  • 你是一个真正的专业人士,正在做一个严肃的项目.

你可以说你已经有了一个专门的测试部门, 执行测试并在需要时编写新测试的一组人. 但是,您能想象在向项目添加新功能后修复bug需要多长时间吗?

测试解决什么问题?

首先,让我们决定哪些问题可以通过测试来解决. 你不可能通过测试消除所有的错误, 但是你可以在测试用例中描述预期的行为. 错误可能在您的测试用例中. 即使在使用测试用例时,面条式代码仍然是面条式代码.

然而, 您可以确保您的代码之后会被修改(通过修复错误), 或者添加新功能), 因此,您的代码仍然不会出现测试中描述的错误. 除了, 即使是编写良好的测试有时也可能用于文档,因为在文档中您可以看到典型场景是如何展开的,并检查预期的行为. 我们可以说,测试是未来的一项小而关键的投资.

那么我们可以使用什么样的测试呢?

基本单元测试通常是不够的. 它们需要得到集成测试、功能测试和验收测试的支持.

基本单元测试通常是不够的. 它们需要得到集成测试、功能测试和验收测试的支持.
  • 单元测试: 低级测试检查代码的一小部分——将类的方法与其他代码隔离开来.
  • 集成开发测试: 集成测试检查应用程序的一部分, 它们可能包含几个类或方法, 但应该限制在一个功能上. 这个测试还应该检查不同的类是如何交互的.
  • 功能测试: 测试对应用程序的特定请求:浏览器响应、数据库更改等等.
  • 验收测试: 在大多数情况下,验收测试意味着检查应用程序是否满足所有客户需求.

为了澄清,假设我们用一些有形的东西来说明这个过程,比如一座建筑物. 建筑物是由构成墙壁的小块组成的. Each brick has to meet specified requirements; it has to withst和 the required load, 有特定的体积和形状, 等等......。. 这些是单元测试. 集成测试的理念是检查砖块彼此粘附的紧密程度和准确性, 它们是如何融入建筑的某个元素的. 功能测试可以比作在建筑物的一面墙上进行测试, 检查内部是否受到保护, 是否有可能透过窗户看到太阳. 验收测试包括将整个建筑作为一个完整的产品进行测试, 进去, 把门关上, 打开灯, 爬到二楼,看看楼外的花园.

满足Codeception

然而,这种划分是 有条件的 有时很难抵制混合不同类型测试的诱惑.

许多开发人员使用单元测试,并声称这就足够了. I used to be one such developer; I found using different systems for different types of 测试 too difficult 和 time-consuming. 不久前,我决定找一些比 PHPUnit); I wanted to be better at testing my code, 但我不想阅读和学习大量的文档并寻找陷阱. 我就是这样发现了Codeception. 起初, 我很怀疑, 就像我们经常遇到的新事物一样(这个项目已经5年了), 所以在技术上, 它不能被认为是“新的”)。, 但在摆弄了几天之后, 我的结论是,Codeception是一个非常有用和强大的系统.

那么如何安装Codeception呢? 这很简单:

$ 作曲家 require "codeception/codeception"
$ PHP vendor/bin/codecept bootstrap

安装完成后,您会发现一个名为 测试 在您的项目中,会有一些子文件夹名为 验收、功能单位. 看起来我们可以开始编写测试了. 很酷,但接下来呢?

现在,试着添加一个标准 验收 Hello World测试.

$ php vendor/bin/codecept

现在,我们得到一个验收测试文件测试/验收/HelloWorldCept.Php,包含以下内容:

wantTo('perform actions 和 see result');

默认变量,名为 $I, is not just a letter; it is a character. 进行测试的是什么?? 很明显,测试员. 这个测试者打开你网站的页面或类, 用它做点什么, 并向你展示其行为的最终结果. 你会看到什么是有效的,什么是错误的. 这就是这个天体被命名的原因 $I 以及为什么它包含调用 想(), 见() or amOnPage ().

因此,让我们像测试人员一样考虑检查页面可操作性的方法. 第一种方法是打开页面并搜索一个短语. 它证明该页面对访问者是可用的.

这应该很简单:

amOnPage('/');
$I->see('Welcome');

我们可以使用这个命令来运行Codeception的测试:

$ PHP vendor/bin/codecept run

我们马上就能看出有什么不对劲. 乍一看, 这条信息似乎太长太不清楚了, 但当我们更仔细地看, 一切都变得显而易见.

突然摔倒! 出了什么问题. 这就是测试的全部意义. 检查信息,找出错误,并从错误中吸取教训.

突然摔倒! 出了什么问题. 这就是测试的全部意义. 检查信息,找出错误,并从错误中吸取教训.

我们做了一个测试, 验收,它检测到一个错误:

验收测试(1)
执行操作并查看结果(HelloWorldCept) Error

----------
1)执行操作失败,并在HelloWorldCept (测试/验收/HelloWorldCept)中看到结果 .php)
[GuzzleHttp\Exception\ConnectException] cURL错误6:无法解析host: 本地主机(参见http://curl).haxx.se / libcurl / c / libcurl-errors.html) 

这就是罪魁祸首: 本地主机 不可用.

下面是我们测试的场景步骤:

 1. $I->amOnPage("/")

好的,让我们打开测试/验收.套件.Yml和更改 url: http://本地主机/变成实际可用的东西. 在我的例子中,它是我的本地测试主机, url: http://local.codeception-article.com/

再次运行测试,这就是你应该得到的结果:

验收测试(1 ) ---------------------------------------------------------------------------------------
执行动作和结果(HelloWorldCept) Ok

万岁! 我们第一次成功的测试!

当然, amOnPage () 不是唯一可用的测试方法吗,我们只是把它挑出来作为我们的例子. 所有Codeception测试方法可分为以下几组:

  • 与页面交互: fillField (), selectOption (), submitForm (), click ()
  • 断言. 见(), dontSee (), seeElement (), seeInCurrentUrl (), seeCheckboxIsChecked (), seeInField (), seeLink (). 对于所有这些方法,您可以添加一个后缀,并在您需要一个在找不到某些东西时不会中断测试场景的方法时使用它.
  • Cookie方法: setCookie (), grabCookie (), seeCookie ()
  • 测试场景的注释和描述: amGoingTo (), 想(), 期望(). 使用这些方法获得注释和描述良好的测试, 哪个能帮助你记住考试的目的.

因此,如果我们要测试密码重置电子邮件页面,我们可以这样做:

wantTo('Test forgotten password 功能ity');
$I->amOnPage('/forgotten')
$I->see('Enter email');
$I->fillField('email', 'incorrect@email.com”);
$I->click('Continue');
$I->expect('Reset password link not sent for incorrect email');
$I->see('Email is incorrect, try again');
$I->amGoingTo('Fill correct email 和 get link');
$I->see('Enter email');
$I->fillField('email', 'correct@email.com”);
$I->click('Continue');
$I->expect('Reset password link sent for correct email');
$I->see('Please check your email for next instructions');

看起来应该这样做,但是如果页面上有一些ajax加载的部分怎么办? 我们能测试这样一个页面吗? 答案是Codeception默认使用基于Symfony BrowserKit和Guzzle的PhpBrowser. 它简单,快速,你只需要卷曲使用它.

您还可以使用Selenium并在实际浏览器中测试页面. 是的,它会慢一些,但是您也可以测试JavaScript.

首先,您需要安装Selenium驱动程序,更改验收.套件.yml并重新构建验收Tester类. 在此之后,您可以使用方法 wait ()waitForElement (). 而且,更有趣的是,您将能够通过使用方法节省时间和资源 saveSessionSnapshot ()loadSessionSnapshot (). 此方法允许您存储会话状态并在早期会话中启动新测试. 这在某些情况下是有用的,例如,在测试授权过程中.

因此,我们最终获得了一个简单但功能强大的功能,可以测试许多函数.

功能测试

好了,是时候进行功能测试了.

$ php vendor/bin/codecept

这就是我们得到的结果:

amOnPage('/');
$I->see('Welcome');

等等,?

不,这不是错误. 功能测试应该和集成测试一样编写. 不同之处在于,功能测试直接与应用程序交互. 这意味着您不需要web服务器来运行功能测试, 并且您有更多的能力来测试应用程序的不同部分.

它确实意味着缺乏对所有框架的支持, 但支持的框架列表很广泛:Symfony, Silex, Phalcon, Yii, Zend框架, 流明, Laravel. 对于大多数情况和大多数开发人员来说,这应该足够了. 请查阅Codeception的模块文档以获取可用函数列表,然后将其打开即可 功能.套件.yml.

Codeception支持主要框架:Symfony, Silex, Phalcon, Yii, Zend框架, 流明, Laravel.

Codeception支持主要框架:Symfony, Silex, Phalcon, Yii, Zend框架, 流明, Laravel.

在我们继续进行单元测试之前,请允许我讲一点题外话. 正如您可能已经注意到的,我们使用以下关键字创建了我们的测试:

$ php vendor/bin/codecept

这并不是创建测试的唯一方法. 也有 c测试. 不同之处在于你可以在一个类中构建多个相关的场景:

$ php vendor/bin/codecept
amOnPage('/forgotten')
    }

    公共函数_after(验收Tester $I)
    {
    }

    / /测试
    公共函数testEmailField(验收Tester $I)
    {
	$I->see('Enter email');

    }
    公共函数testIncorrectEmail(验收Tester $I)
    {
	$I->fillField('email', 'incorrect@email.com”);
	$I->click('Continue');
	$I->see('Email is incorrect, try again');
    }
    公共函数testCorrectEmail(验收Tester $I)
    {
	$I->fillField('email', 'correct@email.com”);
	$I->click('Continue');
	$I->see('Please check your email for next instructions');
    }
}

在本例中,方法 _before ()_after () 在每次测试之前和之后运行. 的实例 验收Tester 类被传递给每个测试,因此您可以像在测试中一样使用它. 这种类型的测试在某些情况下可能很有用,因此值得记住.

单元测试

是时候进行单元测试了.

Codeception是基于PHPUnit)的,所以你可以使用为PHPUnit)编写的测试. 要添加新的PHPUnit)测试,请使用以下方法:

$ php vendor/bin/codecept生成:php单位 单位 HelloWorld

或者只是继承你的测试 \ PHPUnit)_Framework_TestCase.

但如果你想要更多的东西,你应该试试Codeception的单元测试:

生成测试单元HelloWorld
setEmail('correct@email.com”);
	$user->save();
	$user = user::find(1);
	$this->assertEquals('correct@email.com', $user->getEmail());
    }
}

现在没什么不寻常的. 方法 _before ()_after ()设置()tearDown () 类似并将在每次测试之前和之后运行.

该测试的主要优点在于它能够通过包含可以在其中打开的模块来扩展您的测试过程 单位.套件.yml:

  • 访问memcache和数据库跟踪更改(MySQL, SQLite, PostgreSQL, MongoDB支持)
  • REST/SOAP应用程序的测试
  • 队列

每个模块都有自己的特点, 因此,在进行实际测试之前,最好检查文档并收集每个模块的必要信息.

另外,您可以使用Codeception/Specify包(需要添加到 作曲家.json),并写如下描述:

user = User::find(1);
   }
    testUserEmailSave()
    {
	$this->specify("email can be stored", function() {
            	$this->user->setEmail('correct@email.com”);
		$this->user->save();
		$user = user::find(1);
            	$this->assertEquals('correct@email.com', $user->getEmail());
        	});
    }
}

这些闭包函数中的PHP代码是隔离的, 因此,内部的更改不会影响到其他代码. 描述将帮助您使测试更具可读性,并且更容易识别失败的测试.

作为可选的附加选项,您可以使用package Codeception \验证 类似bdd的语法:

getEmail())->equals('correct@email.com”);
}

当然你也可以用存根:

 'correct@email.com ']);
        $this->assertEquals('correct@email.com', $user->getEmail());
}

结论:共同欺骗节省了时间和精力

那么你对Codeception有什么期待呢? 是给谁的?? 有什么需要注意的吗?

Codeception可以被不同PHP熟练程度的开发人员和各种规模的团队使用.

Codeception可以被不同PHP熟练程度的开发人员和各种规模的团队使用.

在我看来, 这个测试框架适用于各种不同的团队:大型和小型, 初学者和 久经沙场的PHP专家一种是使用流行框架,另一种是不使用任何框架.

无论如何,这一切都归结为: Codeception即将迎来黄金时期.

它是一个成熟且文档齐全的框架,可以很容易地被许多模块扩展. 共同欺骗是现代的, 而是基于久经考验的PHPUnit), 这应该让那些不想做太多实验的开发者放心.

它的性能很好,这意味着它很快,不需要太多的时间和精力. 更好的是, 它相对容易掌握, 丰富的文档应该有助于轻松的学习过程.

Codeception也很容易安装和配置,但它拥有很多高级选项. 虽然大多数用户不需要所有的(或确实, 他们中的大多数, 这完全取决于你打算用它做什么. 你可以从基础开始,额外的功能迟早会派上用场.

就这一主题咨询作者或专家.
预约电话
瓦西里·科瓦尔的头像
瓦西里•Koval

位于 基辅,乌克兰

成员自 2015年11月15日

作者简介

Vasily是一名拥有超过9年丰富开发经验的web开发人员, 优化, 支持web应用程序.

Toptal作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.

专业知识

工作经验

20

世界级的文章,每周发一次.

订阅意味着同意我们的 隐私政策

世界级的文章,每周发一次.

订阅意味着同意我们的 隐私政策

Toptal开发者

加入总冠军® 社区.