In the introduction to testing article, we took a quick look at functional testing and why you would need to write them. Now, let's actually see how to write them.
There are primarily two tools used to write functional/acceptance tests in PHP, Codeception and Behat. As you know from the title, we'll use Codeception in this tutorial; too many reasons; the main one is because it's easier to learn.
You may be thinking now “what is that acceptance testing?”. The answer to this may require a full post on its own (if not more)! However, to give you a quick idea, you can think of it the same as functional testing, but written more specifically for the customer — someone who usually doesn't understand the code.
So it's sometimes thought of as more black-box testing than functional testing. In other words, you don't have much control on the tests as you have with functional testing (like seeing what the database contains after executing some code).
I know this isn't a satisfying answer. And you know what? You should not spend too much time on these jargons — believe me, there's yet more to encounter — and instead learn something more practical to use in your projects.
In a new directory, install Codeception via composer:
composer require codeception/codeception --dev
In vendor/bin, you'll get codecept binary file — which we'll use. To make sure it was installed successfully, run this:
vendor/bin/codecept
Or create an alias and run codecept
instead.
To start using Codeception, we need first to bootstrap it. We do that by running:
codecept bootstrap
That will create a bunch of files in a new directory called tests.
For basic uses, you'll need to know these files — acceptance.suite.yml, functional.suite.yml, and unit.suite.yml. Those are used for configuration purposes. You can check out the documentation to see what options are available to you.
In this tutorial, however, we'll only use it to add the web driver that will run our tests.
Let's do this now. Open up functional.suite.yml in your editor and add PhpBrowser as our web driver.
class_name: FunctionalTester
modules:
enabled:
# add framework module here
- PhpBrowser:
url: http://localhost:8000
- \Helper\Functional
Note how we specified the url. This is what we'll use to serve our application. We'll do that basically by running a simple php server, using this command:
php -S localhost:8000
We need first to tell Codeception to generate a new test file in order to write our tests in. To do that, run this:
codecept generate:cept functional Greeting
We gave this command two arguments, the suite and the test name. So this should create a new file named GreetingCept.php in the tests/functional directory.
Open up this file. You should see this:
$I = new FunctionalTester($scenario);
$I->wantTo('perform actions and see result');
The first line is to initialize the tester class, which we'll use to write our tests. The second line is to give a description of what we're testing — it's usually a good practice to write a clean description, as it'll give you a useful test report when you run them.
In this case we're testing to see if a welcoming message appears on the homepage. So, change it to something like this:
$I->wantTo('display a welcoming message on the homepage');
There are many methods we can use on the $I
object. The documentation has a full list of those. However, you'll notice that you can guess most of them naturally.
Here's what we should write for our test:
$I->amOnPage('/');
$I->see('Hello, World!');
Pretty easy to read, isn't it?
Now, let's try to run the tests — they'll, of course, fail.
We run tests in Codeception with this command:
codecept run
To run all tests in a specific suite, for example the functional suite:
codecept run functional
This will fail. And it'll show you what causes that error.
Let's make it pass by creating index.php and echoing "Hello, World!".
<?php
// index.php
echo "Hello, World!";
Run it. It should pass.
Let's try what we've learned with another slightly more sophisticated example.
We'll create a page with a form containing a text input and a submit button. When the user submits the form with some text, s/he'll get a response with that text but reversed.
First, let's write the test and describe what it should do. Generate a new functional test with this command:
codecept generate:cept functional Reverse
Then, put in this code:
$I = new FunctionalTester($scenario);
$I->wantTo('reverse some string');
$I->amOnPage('/reverse.php');
$I->fillField('text', 'HelloWorld');
$I->click('Reverse');
$I->see('dlroWolleH');
This will fail if you run it. To make it pass, put this code in a new file called reverse.php:
<?php
if (isset($_POST['text']))
{
echo strrev($_POST['text']);
exit;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>String Reverse</title>
</head>
<body>
<form method="post">
<input type="text" name="text">
<button type="submit">Reverse</button>
</form>
</body>
</html>
Is some cases, you'd need to test something that runs with javascript (like using animations). Using the PHP Browser web driver won't work as expected. For those things we usually use a tool called Selenium.
With selenium the tests will run on an actual browser. The browser will open (you'll see it), and it will run the actions you've written in your tests — like filling in a field and clicking on a button.
Using Selenium is pretty easy. First, download it from this page. Then, run it in your terminal using java, like this:
java -jar selenium-server-standalone-2.52.0.jar role -hub
Finally, change the web driver in functional.suite.yml to use it.
class_name: FunctionalTester
modules:
enabled:
- WebDriver:
url: http://localhost:8000
browser: firefox
# add framework module here
- \Helper\Functional
Now run the tests again and see what happens. Cool, isn't it?
You can check the documentation for more details, but a common test method you'll use is $I->waitForElement('#element', 30)
. This will allow you to wait for an element before executing any tests on it — which is pretty useful!
This tutorial was intended to give you a quick overview on using Codeception and to write functional tests with it. Actually, we barely scratched the surface here. Nevertheless, I think you're now able to explore this tool more on your own very easily.
I'm a freelance web developer. Laravel & VueJS are my main tools these days and I love building stuff using them. I write constantly on this blog to share my knowledge and thoughts on things related to web development... Let's be friends on twitter.