实用测试者的想法

Let’s start with a confession: you don’t write tests. You know you should, but you don’t. I can’t fault you for it – there are many common issues that prevent developers from writing tests.

让我们开始坦白:您不编写测试。 您知道应该,但您不应该。 我不能为您打扰-有很多常见问题阻止开发人员编写测试。

One misconception though is that unit testing is irrelevant. Here’s how it usually plays out: the developer thinks, “I need to do unit tests, and I should use PHPUnit because it’s a standard. I don’t know much about it, though.” Then he visits the PHPUnit site and reads the first chapter of the documentation, then the second, then the third… and is left scratching his head. “Does everyone write calculators in PHP? I develop web applications. Why am I shown how to test calculators?” What happens next? The developer closes documentation thinking that testing is somehow related to calculators and is too complex for him understanding at the moment.

一个误解是单元测试无关紧要。 通常是这样的:开发人员认为:“我需要进行单元测试,并且应该使用PHPUnit,因为它是标准。 不过,我对此并不了解。” 然后,他访问PHPUnit网站,阅读文档的第一章,然后阅读第二章,然后阅读第三章……然后挠头。 “每个人都用PHP编写计算器吗? 我开发Web应用程序。 为什么要显示如何测试计算器?” 接下来发生什么? 开发人员在关闭文档时认为测试在某种程度上与计算器有关,并且对于他目前的理解而言过于复杂。

Maybe something similar happened to you. Maybe not. But you really should know what to test and how to test it. Such knowledge comes from experience, so in this article I’ll share some of my experience with unit testing. (Please accept my apologies beforehand should I exaggerate a little and am somewhat inaccurate at times; my goal is to help you start writing tests and a little puffery helps the cause.)

也许您发生了类似的事情。 也许不会。 但是您确实应该知道要测试什么以及如何对其进行测试。 这些知识来自经验,因此在本文中,我将分享一些单元测试的经验。 (如果我有点夸张,有时不准确,请事先接受我的道歉;我的目标是帮助您开始编写测试,而一点点浮肿可以帮助您解决问题。)

功能测试 (Functional Testing)

There is no problem with PHPUnit, and there are no problems with the professional developer who decided to write that first unit test. There is a problem with the assumption that unit testing is always the right thing to start with. What is your project? I suppose it is a web application, and you should test it as a web application! How a web application is tested? You open a web page, click on some links, fill in a form, and see the expected results. That’s what your customers do, so why would you start testing your application any other way? Of course as a developer you can improve testing by automating the process. And that’s the main idea of acceptance or functional testing.

PHPUnit没有问题,决定编写第一个单元测试的专业开发人员也没有问题。 假设单元测试始终是正确的开始是一个问题。 你的项目是什么? 我想它是一个Web应用程序,您应该将它作为Web应用程序进行测试! 如何测试Web应用程序? 您打开网页,单击某些链接,填写表格,然后查看预期结果。 那就是您的客户所做的事情,那么您为什么要以其他方式开始测试您的应用程序呢? 当然,作为开发人员,您可以通过自动化过程来改善测试。 这就是验收或功能测试的主要思想。

Wikipedia says this about functional testing:

Wikipedia谈到了有关功能测试的内容:

Functional testing is a type of black box testing that bases its test cases on the specifications of the software component under test. Functions are tested by feeding them input and examining the output, and internal program structure is rarely considered.

功能测试是一种黑盒测试,其测试用例基于被测软件组件的规范。 通过输入功能并检查输出来测试功能,而很少考虑内部程序结构。

For sure, PHPUnit can be used for functional testing. But PHPUnit is not the only tool available. As you may know, Selenium IDE is widely used. We could use it too, but let’s face it… we’re PHP developers and prefer PHP tools for testing.

当然,PHPUnit可用于功能测试。 但是PHPUnit不是唯一可用的工具。 您可能知道, Selenium IDE被广泛使用。 我们也可以使用它,但让我们面对现实吧……我们是PHP开发人员,更喜欢使用PHP工具进行测试。

Codeception is a modern testing framework. A simple acceptance (or functional) test can be written with it using a very simple PHP DSL (domain-specific language). Here’s an example:

Codeception是一个现代的测试框架。 可以使用非常简单PHP DSL(特定于域的语言)编写简单的接受(或功能)测试。 这是一个例子:

<?php
$I = new WebGuy($scenario);
$I->wantTo("send a feedback");
$I->amOnPage("/");
$I->click("Feedback");
$I->see("Submit your feedback");
$I->fillField("Body","Your site is great!");
$I->click("Submit");
$I->see("Thanks for your feedback!");

The code checks that we can submit feedback from a site. It executes or emulates a browser and performs defined actions within the site. All assertions are based on page content. If we don’t see the text “Thanks for your feedback” in the last response, the test fails. Simple, right?

该代码检查我们是否可以从网站提交反馈。 它执行或模拟浏览器并在站点内执行已定义的操作。 所有断言均基于页面内容。 如果我们在上一个回复中没有看到“感谢您的反馈”文本,则测试失败。 简单吧?

Why not start by describing all your features as tests? Just write the common usage scenarios and execute them on your site. Functional testing proves a user is able to reproduce your steps and see the same results and thus your application functions well.

为什么不从将所有功能描述为测试开始呢? 只需编写常见的使用场景并在您的站点上执行它们即可。 功能测试证明用户能够重现您的步骤并看到相同的结果,因此您的应用程序运行良好。

As an alternative, you could consider using other popular tools like PHPUnit and Mink, Behat, or Selenium IDE.

作为替代方案,您可以考虑使用其他流行的工具,例如PHPUnit和MinkBehat或Selenium IDE。

单元测试 (Unit Testing)

But what about unit tests… when do they come in handy? Let’s start with a definition, again from Wikipedia:

但是单元测试呢?它们什么时候派上用场呢? 让我们从Wikipedia再次定义:

Unit testing is a method by which individual units of source code are tested to determine if they are fit for use. A unit is the smallest testable part of an application. In procedural programming a unit could be an entire module but is more commonly an individual function or procedure. In object-oriented programming a unit is often an entire interface, such as a class, but could be an individual method.

单元测试是一种测试源代码的各个单元以确定它们是否适合使用的方法。 单元是应用程序中可测试的最小部分。 在过程编程中,一个单元可以是整个模块,但更常见的是单个功能或过程。 在面向对象的编程中,一个单元通常是一个完整的接口,例如一个类,但可以是一个单独的方法。

Unit testing is about testing your code and your internal APIs. There is really one rule when it comes to deciding when to do unit testing: when you write your own classes, modules, libraries, frameworks, etc. it is absolutely necessary to cover them with unit tests.

单元测试是关于测试您的代码和内部API。 在决定何时进行单元测试时,确实有一条规则:当您编写自己的类,模块,库,框架等时,绝对有必要用单元测试来覆盖它们。

But what about the “calculator problem?” Let’s state it again. We don’t write calculators, rather we build web sites on top of MVC frameworks and CMSs. Frameworks delegate most of the routine tasks, and as a result our code does nothing more than trigger methods of the framework’s API. But the framework’s API is already tested by its developers, so why should we test it again?

但是“计算器问题”呢? 让我们再说一遍。 我们不编写计算器,而是在MVC框架和CMS之上构建网站。 框架委托了大多数例行任务,因此我们的代码只不过是框架API的触发方法而已。 但是框架的API已经由其开发人员进行了测试,那么为什么还要再次对其进行测试?

What you see here is a problem with most popular MVC frameworks; there is just no simple convention as to where the business logic is stored. If we want to test the feature “a page can be created”, we should test a controller that takes parameters from a form that passes it to a model that validates and saves it. There is no unit responsible for the page creation, that is, there is no single function or class that creates a page. To test one feature we need three or more unit-tests in different modules. Is that rational? I’d say it’s a waste of time. One functional test to check that “a page can be created” is sufficient.

您在这里看到的是大多数流行的MVC框架存在的问题。 关于业务逻辑的存储位置,没有简单的约定。 如果要测试“可以创建页面”功能,则应该测试一个控制器,该控制器从表单中获取参数,然后将其传递给验证并保存模型。 没有负责页面创建的单元,也就是说,没有单个函数或类来创建页面。 要测试一项功能,我们需要在不同的模块中进行三个或更多的单元测试。 那合理吗? 我会说这是浪费时间。 一项用于检查“可以创建页面”的功能测试就足够了。

If your functional tests already check everything a user can do, unit tests are great to test things user is forbidden to do. It’s impossible to predict all the actions user can perform on the site, but within unit tests you can verify particular actions aren’t carried out – a user isn’t saved into the database without an email address, no two users can be created with the same login, etc. Write unit tests to check the validation rules for your forms and models, security rules for your controller, and so on.

如果您的功能测试已经检查了用户可以执行的所有操作,则单元测试非常适合测试用户被禁止执行的操作。 无法预测用户可以在站点上执行的所有操作,但是在单元测试中,您可以验证未执行特定操作–没有电子邮件地址就无法将用户保存到数据库中,无法使用创建两个用户相同的登录名,等等。编写单元测试以检查表单和模型的验证规则,控制器的安全规则等等。

There are various circumstances that can’t be reproduced with functional tests. Let’s say for example every 100th member of your site receives some sort of bonus. Should you register 100 users manually just to check the last one will receive her bonus? Probably not. A unit test for such a feature is needed. Here instead is a sample PHPUnit test case:

功能测试无法重现各种情况。 举例来说,假设您网站的第100位成员获得某种奖励。 您是否应该手动注册100个用户以检查最后一个将获得她的奖金? 可能不是。 需要对此功能进行单元测试。 这里是一个示例PHPUnit测试用例:

<?php
class BonusTest extends PHPUnit_Framework_TestCase
{
    public function setUp() {
        $this->bonus = new Bonus();
    }

    public function testProvideBonusTo100thUser() {
        // let's check there are 99 losers
        for ($i=0; $i < 99; $i++) {
            $user = new User();
            $user->setName(uniqid());
            $user->save();
            $this->assertFalse($this->bonus->hasBonus($user));
        }
        // and only one winner
        $user = new User();
        $user->setName("Winner!");
        $user->save();
        $this->assertTrue($this->bonus->hasBonus($user));
    }
}

As a tool for unit-testing, you can use either PHPUnit, or another modern testing framework like Atoum or EnhancePHP. They are designed to be less “enterprisey,” and as such are easier to get acquainted with for novices. If you prefer to test in Ruby style, check out PHPSpec or Spectrum. Moreover, the aforementioned testing framework Codeception can be used to test your code in a similar manner as it tests your site.

作为单元测试的工具,您可以使用PHPUnit或其他现代测试框架(例如AtoumEnhancePHP) 。 他们的设计目的是减少“企业精神”,因此对于新手来说更容易结识。 如果您想以Ruby风格进行测试,请查看PHPSpecSpectrum 。 此外,上述测试框架Codeception可用于测试您的代码,就像测试您的站点一样。

摘要 (Summary)

Write your tests pragmatically. Use functional (acceptance) tests for testing your application’s behavior and use unit tests for testing its code. It’s important to test common usage, situations of improper usage, and rare events. But remember, even 100% code coverage won’t guarantee code quality or stability.

务实地编写测试。 使用功能(接受)测试来测试应用程序的行为,并使用单元测试来测试其代码。 测试常见用法,用法不正确的情况和罕见事件非常重要。 但是请记住,即使100%的代码覆盖率也无法保证代码的质量或稳定性。

Image via John Kwan / Shutterstock

图片来自 君( John Kwan) / Shutterstock

翻译自: https://www.sitepoint.com/thoughts-of-a-pragmatic-tester/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值