Codeception tutorial acceptance test

In this Codeception tutorial you’ll learn how to write a test for a user story for the search function at the OXID corporate blog. Automated tests offer many advantages for customers, agencies and developers. Apparently, they save a lot of time and resources. Since the tests run eight times as fast as manual tests, this is of course a strong argument. But tests are also more precise and more reliable than humans. They always delete their browser cache and never use auto-completion on a form. Even more important, especially in the realm of e-commerce, is the reliability of the software to the user, because trust is very important here. However, this article is less about the question of why tests are used than about the implementation.

Acceptance criteria for a search in the Codeception tutorial

An acceptance aest is a frontend test or end to end test. A user story is described in concrete terms. In our case it is about the search form. In a first test, we map a valid search. In further tests also wrong data would be possible or also the attempt to enter a script tag, and this way to examine security criteria.

  • open the search form
  • enter “e-commerce”
  • at least one autosuggestion entry has the search string in the headline
  • the link to “all results” is structured according to the desired scheme
  • click on the search button leads to the URL
  • the search form is prefilled with the search string on the results page
  • several headlines in the result contain the search string
  • the search string can also be found in the headline
  • ten search results will be displayed
  • more than 150 articles have been found
  • the search string is also included in the number of results output
  • the search string is also on the page title

Tests also aim to ensure that they are reproducible and unique. They therefore meet very specific criteria. With manual tests it is quite complex for testers to test correctly. You can already see from this very simple example how complex this can become.

Legacy projects – Codeception as a standalone application

Codeception can perform tests as a standalone application. The database can also be accessed here. This use case is particularly suitable for acceptance and API tests with Codeception. This is especially good for testing legacy code applications. Here it can naturally come to conflicts with the dependency management or issues with the current PHP versions. After all, tests are there to get out of these situations. In the current folder you can generate a composer.json with the git init && composer init command via the wizard. It is important to work directly with Git at this point so that the Codeception wizards do everything correct during the bootstrap process.

composer.json
{
    "name": "rolandgolla/oxid-blog-cc",
    "require-dev": {
        "codeception/codeception": "^2.5"
    },
    "authors": [
        {
            "name": "Roland Golla",
            "email": "rolandgolla@gmail.com"
        }
    ],
    "require": {}
}

It is important that there is a dev dependency. Tests should not be executable live for security reasons and of course the dependencies should not be transferred into the project.

Then we use vendor/bin/codecept bootstrap and get a test folder. As we only work with acceptance tests here, we can also delete the files functional.suite.yml and unit.suite.yml in the tests folder and concentrate on the essentials. Of course, this also applies locally to the two folders “unit” and “functional”, which however would not be included in Git. Under tests/_support/_generated there are also the two files FunctionalTesterActions.php and UnitTesterActions.php, which can also be removed. Same for Functional.php and Unit.php under tests/Helper.

The standard configuration files are not sufficient for practical use. Some changes have to be made here:

  • codeception.yml:
namespace: Tests/Oxid
actor: Tester
paths:
  tests: Tests
  log: Tests/_output
  data: Tests/_data
  support: Tests/_support
  envs: Tests/_envs
settings:
  colors: true
  memory_limit: 1024M
  shuffle: true
extensions:
  enabled:
    - Codeception\Extension\RunFailed
modules:
  config:
    WebDriver:
      url: 'https://blog.oxid-esales.com'
      browser: chrome
      window_size: 1600x1000
      connection_timeout: 5
      request_timeout: 30
      clear_cookies: false
      capabilities:
        unexpectedAlertBehaviour: 'ignore'

A small explanation: a namespace has been given here. This of course makes it much easier to work in actual projects. And here is also the file in which configurations are stored. This is a small change compared to the standard template. Basically the configuration for a suite results from both files. This involves a merge with an overwrite. In practical use, however, DevOps has shown that it is better to manage configuration variables in one place. Then it is easy to handle. All other information is self-explanatory at this point.

  • tests/acceptance.suite.yml
class_name: AcceptanceTester
modules:
  enabled:
    - WebDriver
    - Asserts
env:
  firefox:
    modules:
      config:
        WebDriver:
          browser: 'firefox'

The acceptance suite configuration contains the actual configuration for the acceptance tests. Here you define which modules are loaded. At this point it would also be possible to load the DB module and check form entries directly in the database. Now only the web driver and the asserts are used. Changes to config files become effective with the command “vendor/bin/codecept build“.

The first test – Codeception tutorial

We want to write a test for the search. In any case, it makes sense to bring the tests directly into a folder structure and keep them clearly arranged. This makes it easier to group tests together. It is important to generate a “cest” at this point. This is a class that simply offers much more and better possibilities. The first thing to do is to create a page object. Here you can swap out the HTML markup and manage it much easier. Tests become re-usable for different projects.

vendor/bin/codecept g:pageobject Startpage
tests/_support/Page/Startpage.php
namespace Tests\Oxid\Page;

class Startpage
{
    // include url of current page
    public static $URL = '/';

    public static $searchOpener = '#menu-item-search > a';
    public static $searchInput = '#s';
    public static $searchButton = '#searchsubmit';

    public static $searchResultPageHeadline = 'h4.extra-mini-title';
    public static $searchResultItemHeadlines = 'h2.post-title';
    public static $searchResultInput = '#searchform > div > input[type="text"]:nth-child(2)';
}

As soon as you start writing and using tests, you directly improve your code. This is as true for PHP code as it is for HTML code. Good selectors play a crucial role here. This example clearly shows that the search entry on the result page causes problems, the slightest change in HTML would cause the test to fall. However, if you clicked manually, everything would be correct. Such circumstances cause a bad image during the tests and you lose confidence.

Then it comes to the test:

vendor/bin/codecept g:cest acceptance search/Search 
tests/acceptance/search/SearchCest.php
namespace Tests\Oxid\search;

use Tests\Oxid\AcceptanceTester;
use Tests\Oxid\Page\Startpage;

class SearchCest
{
    public function _before(AcceptanceTester $I, Startpage $page)
    {
        $I->amOnPage($page::$URL);
        $I->waitForElement($page::$searchOpener);
    }

    public function searchWithValidWordIsWorking(AcceptanceTester $I, Startpage $page)
    {
        $searchString = 'e-commerce';
        $I->click($page::$searchOpener);
        $I->fillField($page::$searchInput, $searchString);
        $I->click($page::$searchButton);

        $I->waitForElementVisible($page::$searchResultPageHeadline);
        $I->canSeeInCurrentUrl('s=' . $searchString);
        $I->assertEquals($searchString, $I->grabValueFrom($page::$searchInput));
        $I->assertEquals($searchString, $I->grabValueFrom($page::$searchResultInput));

        $headlines = $I->grabMultiple($page::$searchResultItemHeadlines);
        foreach ($headlines as $key => $headline) {
            $I->assertContains($searchString, strtolower($headline), 'Line: ' . ($key + 1));
        }

        $I->assertEquals(10, count($headlines));
        $count = (int) $I->grabTextFrom($page::$searchResultPageHeadline);
        $I->assertGreaterThan(150, $count);
    }
}

Code coverage is huge

The storefront is the sum of all processes. If a small user story is running here a lot of things are already tested at once. Among other things, it shows that many technologies work properly together. This simple test of the search ensures that the page is loaded correctly and that the database provides the correct data. In addition, the routing and the correct function of the Javascript is ensured. There could be also other components in use, like an Elasticsearch. In addition, of course, all concrete features are tested in connection with the search. This way it is quickly possible to map a very large test coverage with a few frontend tests.

GitHub link

https://github.com/Entwicklungshilfe-NRW/oxid-blog-test

Bottom line

Even a change in the footer can cause a search to crash. Only the storefront is the summary of all processes and therefore a reliable way to test websites for functionality. In general the tests are 8 times faster than manual tests and much more reliable. Codeception also offers PHP developers the possibility to look into the database, to outsource functions and to use known PHP libraries. It is important to write good selectors and reliable tests so that you can continue to trust the tests.



Start the discussion at OXID forums