Quantcast
Channel: Codeception
Viewing all 321 articles
Browse latest View live

Introduction to Codeception

$
0
0

We build web sites with PHP, we build web services and web applications. But is PHP good enough for testing them?

How often do you see PHP projects with no line of test written? From my experience, this situation happens quite often. We should state the unpleasant fact that tests are not so popular around the PHP world. Surely, the advanced developers with 5+ years of experience in PHP and other programming languages understand importance of testing and PHPUnit usage. But juniors and seniors are just skipping testing and, therefore, produce unstable web applications.

From my point of view, the key issue is not in developers themselves. They are pretty good and skilled. But it is PHP that lacks the tools for testing. If you write a site and you want to test its behavior, what is the natural way to do so? Selenium? PHPUnit + Selenium? This tools are powerful, but too complex. Using them is like using a sledgehammer to crack a nut.

For the last two months I have been developing a simple, yet powerful alternative testing framework: Codeception. It focuses on making tests easy to read, easy to write and easy to debug. This code illustrates a common acceptance test in Codeception:

<?php
$I = new WebGuy($scenario);
$I->wantTo('create new blog post');
$I->amOnPage('/blog/posts');
$I->click('Create new post');
$I->fillField('Title','Codeception, a new way of testing!');
$I->fillField('Text','Codeception is new PHP full-stack testing framework.');
$I->click('Send');
$I->see('Congratulations, your post is successfully created!');
?>

It's pretty clear, isn't it? But here goes another feature of Codeception: this code can be executed as a functional test in symfony, Symfony2, Zend Framework, with PHP web scrapper Goutte, or even with Selenium!

Codeception is all about behavior-driven testing. For each part of application you describe user actions and the results you are expecting them to see. Users interact with your web application through a web browser. They open the page, click on links, fill the forms, and in the end they see the site has generated a proper result in response. In Codeception you record user's steps and make testing engine reproduce them. You need a web server running to perform requests through a web browser.

Writing tests is just about choosing actions from a list and injecting proper parameters. IDE autocomplition demo

If you are ready to start writing first Codeception test, just follow the installation steps. After you install package and its dependencies, select a project you want to test (I suppose you have one) and run a bootstrap command in its root:

$ codecept bootstrap

It creates a 'tests' directory with 3 default testing suites:

  • acceptance
  • functional
  • unit

Let's start with the sample acceptance test. We shall save it into 'tests/acceptance/StartPageCept.php'.

<?php
$I = new WebGuy($scenario);
$I->wantToTest('front page of my site');
$I->amOnPage('/');
$I->see('A sample text on my site');
?>

Replace 'A sample text on my site' with the text that actually is on your site. To make it run we should start a local web server with the tested application. The URL of this application should be specified in suite configuration file: 'tests/acceptance.suite.yml'.

    config:
        PhpBrowser:
            url: 'here goes url'

Now a test can be executed with the command run:

$ codecept run acceptance

Then the result is shown:

Suite acceptance started
Trying to see front page of my site (StartPageCept) - Ok

Time: 1 second, Memory: 21.00Mb

OK (1 test, 1 assertions)

Now let's see how forms can be tested. Perhaps the most often used forms are login forms.

<?php
$I = new WebGuy($scenario);
$I->wantTo('log in as regular user');
$I->amOnPage('/login');
$I->fillField('Username','davert');
$I->fillField('Password','qwerty');
$I->click('Login');
$I->see('Hello, davert');
?>

The 'fillField' and 'click' command take element name or CSS selector as paramater. Thus, if you don't use labels for fields, you can rewrite this scenario in the following way:

<?php
$I = new WebGuy($scenario);
$I->wantTo('log in as regular user');
$I->amOnPage('/login');
$I->fillField('form#login input[name=login]','davert');
$I->fillField('form#login input[name=password]','qwerty');
$I->click('form#login input[type=submit]');
$I->see('Hello, davert');
?>

Or this can be shortened to a single command:

<?php
$I = new WebGuy($scenario);
$I->wantTo('log in as regular user');
$I->amOnPage('/login');
$I->submitForm('form#login', array('login' => 'davert', 'password' => 'qwerty'));
$I->see('Hello, davert');
?>

As you can see, tests in Codeception look pretty simple and compact. Testing environment is prepared out of the box, no need for the bootstrap code to be written. You can compare Codeception to Behat, to PHP DSL, but Codeception can do much more than executing scenarios. As you've already seen, it's not limited to acceptance tests only.

Codeception is fully documented, look into the guides for full reference. Codeception is in beta-version, but it will evolve. Use it. Test your applications. Make them stable.

Next time functional tests will be covered.


Released 1.0.1. Please update

$
0
0

This relese fixes two reported bugs.

  • using see commands on pages with <!DOCTYPE
  • using see commands with non-latin characters. PhpBrowser, Selenium, Frameworks modules were updated.

Please update your version via PEAR:

$ pear install codeception/Codeception

or download updated Phar package. It's important to update Codeception now.

In next releases an automatic updater will be added.

Behavior Driven Testing with Zend Framework

$
0
0

Codeception is testing framework in which all tests are written in a single descriptive manner. It's aim is to make tests easy to read, easy to write and easy to debug. Every single test you write can be run either in Selenium, in PHP Browser emulator, or as a functional test for Zend Framework. Today we will look how Codeception can be used for testing your Zend application.

Most of CRUD applications use forms for creating or editing content. It's hard to test every form on site after each release manually. But we will automate this process. For testing Zend applications you probably used it's Zend_Test_PHPUnit class, which is build on top of PHPUnit's TestCase. Codeception is built on top of PHPUnit too. And takes similar approaches from Zend_Test_PHPUnit_ControllerTestCase. But commands available in tests being made intuitively simple and much more human friendly then they are in Zend_Test_PHPUnit.

We take a code from Zend_Test_PHPUnit tutorial:

<?php
// Zend_Test_PHPUnit
$this->request->setMethod('POST')->setPost(array(
'username' => 'foobar',
'password' => 'foobar'
));
$this->dispatch('/user/login');
$this->assertRedirectTo('/user/view');
$this->resetRequest()->resetResponse();

$this->request->setMethod('GET')->setPost(array());
$this->dispatch('/user/view');
$this->assertQueryContentContains('h2', 'User: foobar');
?>

and reproducing it for Codeception:

<?php
// Codeception
$I->amOnPage('/user');
$I->submitForm('form#loginForm', array('username' => 'foobar', 'password' => 'foobar'));
$I->seeInCurrentUrl('/user/view');
$I->see('User: foobar', 'h2');
?> 

It's only 4 lines long, but it does the same as the test above. It tests logging in on site, nothing more, nothing less. We can expect user is logged in if he was moved from '/user' page, to '/user/view' and username is in Heading2 element of that page.

Codeception won't perform asserts for application internals as module/controller/action, as this is not natural to bound functionality into one place. A small refactoring will completely break a test, even if application is running perfectly. For the same reasons Codeception doesn't provide analog for assertQueryCount or assertQuery, because they test a markup probably unseen to user. If a element on page has changed a test will fail, still application can work perfectly. We are testing only elements user can interact with and user can see. This makes tests more stable and drives us to less false negative results.

All the assertXXXX commands is replaced with natural 'see' commands.

  • see - checks if text or element with text is on page
  • seeInCurrentUrl - checks if a url contains specified value
  • seeLink - checks link exist on page
  • seeInField
  • seeCheckboxIsChecked
  • etc...

This commands can accept either CSS locators or element names.

With Codeception you can write tests that will be executed inside a Zend Framework, but will simulate user actions with less technical code. As every test should be readable and thus simple definitions in terms "I do that", "I see this" are better to understand. Especially, if a test is read by new developer.

Today we are going to write tests for open source blog application Lilypad-Zend-Framework-Blog. We assume you already have Zend Framework intalled.

It can be taken from GitHub:

git clone git://github.com/Codeception/ZFBlog.git

Set up database and configure application/configs/application.ini to access it. Default settings are:

resources.db.adapter = "PDO_MYSQL"
resources.db.params.host = "localhost"
resources.db.params.username = "root"
resources.db.params.password = ""
resources.db.params.dbname = "zfblog"

Database should be populated with zend_blog.sql dump from the project root.

To start covering it with tests Codeception should be installed.

Run bootstrap command from root of ZFBlog:

$ codecept bootstrap
$ codecept build

This will create a default test suites. Now some steps for configuration should be done.

For interacting with Zend Framework a ZF1 module is used. It should be enabled in functional tests configuration: tests/functional.suite.yml. For database repopulation after each step add Db module too.

class_name: TestGuy
modules:
  enabled: [ZF1, Db, TestHelper]

We use default settings for ZF1 module to connect to ZFBlog application. We use 'testing' environment and 'application.ini' stored in it's standard place: 'application/configs/application.ini'. But Db module requires additional configuration. We need schema and default data was recreated for each test run. We have database dump, a file named zend_blog.sql in root of project. We should point Codeception to use it for database repopulation. Now update a codeption.yml config in project's root and set proper db credentials.

paths:
    tests: tests
    log: tests/_log
    data: tests/_data
    helpers: tests/_helpers
settings:
    bootstrap: _bootstrap.php
    suite_class: \PHPUnit_Framework_TestSuite
    colors: true
    memory_limit: 1024M
    log: true
modules:
    config:
        Db:
            dsn: 'mysql:host=localhost;dbname=zfblog'
            user: 'root'
            password: ''
            dump: zend_blog.sql

We configured Db credentials and database dump being used. Now let's write some tests. In tests/functional let's create file CreateBlogCept.php:

<?php
$I = new TestGuy($scenario);
$I->wantTo('create new blog post');
$I->amOnPage('/admin');
$I->see('Blog Editing');
$I->click('Add new blog');
$I->see('Add new blog');
?>

Now a test can be run with command.

$ codecept run functional

And here is the expected result.

Codeception PHP Testing Framework v1.0.1
Powered by PHPUnit 3.6.4 by Sebastian Bergmann.

Suite functional started
Trying to  create new blog post (CreateBlogCept.php) - Ok


Time: 2 seconds, Memory: 21.00Mb

OK (1 test, 2 assertions)

To get detailed information of what steps were taken in test, run this command with --steps option. And this is what will be printed:

Trying to  create new blog post (CreateBlogCept.php)
Scenario:
* I am on page "/admin"
* I see "Blog Editing"
* I click "Add new blog"
* I see "Add new blog"
  OK

Also, all executed tests, steps performed and a results of execution, will be written to 'tests/_log' directory.

Try to create your own test for editing post. I hope you will like new way of testing Zend Application. Use Codeception to make your applications stable and predictable.

Support for Zend2 is coming soon.

Codeception 1.0.2 Released.

$
0
0

As you may know, Codeception a BDD-style testing framework has tools for cleaning up tested database between tests. This week tools for database repopulation in Codeception were improved and it's usage was covered in new chapter of Guides. To get your database populated before tests, just provide an SQL dump and set up PDO connection. For functional and unit testing best way to clean up your database faster is not to pollute it at all. All database queries can be taken into transaction and rolled back at test end. This behavior is introduced within new Dbh module, and in ORM modules for Doctrine1 and Doctrine2. To speed up data repopulation in acceptance tests we recommend you to move database to SQLite.

Database repopulation is the subject of the new Guide: Working with Data was started. It explains different strategies for database cleanups and usage of fixtures in Codeception.

Codeception is now tested for loading and cleaning up SQLite, MySQL, and PostgreSQL dumps.

Bugfixes:

  • configuration merged improperly (reported and fixed by zzmaster).
  • steps are printed in realtime and not buffered anymore.
  • asserts on html pages doesn't echo all page texts for strings longer then 500 chars.
  • tests are sorted by name when loading.

Please update your version via PEAR:

$ pear install codeception/Codeception

or download updated Phar package.

Codeception 1.0.3 Released. Generators and Agile Documentation.

$
0
0

This Codeception release is all about minor but useful features. Starting from 1.0.3 you will be notified on every new Codeception release from console. If you are not running tests, Codeception Cli application will check for new version and notify you if it is available.

$ codecept
UPDATE: version 1.0.3 released. See changes on: http://codeception.com.
Codeception version 1.0.2

There are new generators for empty tests: Cest and Cept files. Empty test suite can be generated too. Just check new 'generate:' commands.

Agile Documentation

But the most interesting generation feature is Agile Documentation. From now you can improve your documentation generated by DocBlox by appending test scenarios into text. With Codeception BDD approach to Unit Tests it's easy to imagine every test as usage documentation.

The concept of Agile Documentation will be demonstrated in following example:

We have a sample static method for creating an entity Group. Which can be group of people in social network, for example. This method uses Doctrine 2 as ORM.

<?php
class Group {
    
    // This creates new group by user
    public static function create($name, $founder_id)
    {        
        $em = self::$entityManager;

        $group = new \Model\Group;
        $group->setName($name);
        $group->setUser($em->getRepository('Model\User')->find($founder_id));
        $em->persist($group);
        $em->flush();

        return $group->getId();
    }
}
?>

This method requires Id of user who creates group and group name. Here is test for this function:

<?php
    public function create(\CodeGuy $I)
    {
        $user_id = Fixtures::get('valid_user')->getId();

        $I->wantTo('create group');
        $I->executeTestedMethodWith('DemoGroup', $user_id)
            ->seeInRepository('Model\Group', array('name' => 'DemoGroup', 'user_id' => $user_id, 'type' => 'group'))
            ->seeResultIs('int');
    }
?>    

This test is translated into documentation for Group::create method.

With this method I can create group

If I execute \Service\Group::create("DemoGroup",1)
I will see in repository "Model\Group",{"name":"DemoGroup","user_id": 1, "type": "group" }
I will see result is "int"

Codeception scans for all Cest files and for all classes passed to DocBlox. When tests match the function in documentation the test is processed and appended into function description.

To start using Codeception with DocBlox you should use the same project root for both projects, i.e. codeception.yml and docblox.xml should be in one directory. Include plugin into docblox.xml:

    <plugins>
        <plugin path="{FULL-PATH-TO-PEAR}/Codeception/plugins/DocBlox/Codeception">
        </plugin>
    </plugins>

As you see, you should specify path to PEAR explicitly. This is DocBlox limitation. Plugins can be either local or provided with DocBlox distribution. I'm not sure how to deal with current Codeception plugin for DocBlox, so I asked this question on GitHub. I hope in near future a better solution will be proposed.

Bugfixes

  • replaced suppressed errors with error elimination (thanks to jonphipps)
  • fixed scenario generations
  • fixed generation of html reports

Please update your version via PEAR:

$ pear install codeception/Codeception

or download updated Phar package.

BDD Approach to Unit Testing with Codeception.

$
0
0

Codeception is new BDD-style testing framework for PHP. It makes testing easier than it was before. Yep, really. If you are not a fan of testing, that might as well be because you haven't used the proper tools. We've already showed you how simple it is to automate testing for any web application by writing acceptance tests. Today we will dig deeper into the code and show you how it can be tested.

With BDD approach in Codeception, any test, even the unit test, is written as a scenario. By this scenario you declare what you are doing and what results you expect to see. In traditional xUnit scheme your test is just a piece of code that uses the method being tested. This piece of code becomes a mess when you test complex units depending on other classes or when you need to check data in a database, etc. Codeception always keeps your unit tests simple and readable.

I always start with a model example in the MVC pattern. I am not using any of existing PHP ORMs in the sample code, and this will make the code look a little bit weird. I'm doing this just to demonstrate testing process.

Here we've got a sample model class.

<?php
class User extends AbstractModel {
    
    public function create()
    {
        if (!$this->isNew) throw new ModelException("User already created");        
        if (!$this->role) $this->role = 'member';

        if (!$this->validate()) throw new ValidationException("User is invalid");

        $this->save();
    }
}
?>

Quite a complex method of ORM class, but its usage is really simple:

<?php
$user = new User;
$user->setName('davert');
$user->create();
?>

How is this method tested with Codeception? First of all, we won't be testing any inherited methods like validate or save. They belong to AbstractModel class and are to be tested there. The 'create' method is to be tested in full isolation. For this we will not use the actual User class, but its Stub, i.e. a class with some methods replaced by their dummies.

<?php

use Codeception\Util\Stub;

class UserCest {

    public $class = 'User';
    
    public function create(CodeGuy $I)
    {        
        $I->wantTo('create new user by name');
        $I->haveStub($user = Stub::makeEmptyExcept('User', 'create'));

        $user->setName('davert');

        $I->executeTestedMethodOn($user);

        $I->expect('user is validated and saved')       
            ->seeMethodInvoked($user, 'validate')
            ->seeMethodInvoked($user, 'save');
    }
}
?>

Here we have tested that the 'validate' and 'save' methods were actually invoked. We assume that 'validate' and 'save' are themselves tested; thus, they will work as expected. And if the test fails, we know the source of problem is the 'create' method itself.

However, the test doesn't cover exceptions that may be thrown. Thus let's improve it by making the validate method simulate exceptions.

<?php
use Codeception\Util\Stub;

class UserCest {

    public $class = 'User';
    
    public function create(CodeGuy $I)
    {        
        $I->wantTo('create new user by name');
        $I->haveStub($user = Stub::makeEmptyExcept('User', 'create'));
        $I->haveStub($invalid_user = Stub::makeEmptyExcept('User', 'create', array(
            'validate' => function () { return false; }
        )));     

        $user->setName('davert');

        $I->executeTestedMethodOn($user);

        $I->expect('user is validated and saved')       
            ->seeMethodInvoked($user, 'validate')
            ->seeMethodInvoked($user, 'save');
        
        $I->expect('exception is thrown for invalid user')
            ->executeTestedMethodOn($invalid_user)
            ->seeExceptionThrown('ValidationException','User is invalid');               
            
        $I->expect('exception is thrown while trying to create not new user')
            ->changeProperty($user,'isNew', false)
            ->executeTestedMethodOn($user)                      
            ->seeExceptionThrown('ModelException', "User already created");
    }
}
?>

The only thing we haven't cover in the test is user's default role assertion. In case we store all column values as public variables, we can use the 'seePropertyEquals' method.

<?php

use Codeception\Util\Stub;

class UserCest {

    public $class = 'User';
    
    public function create(CodeGuy $I)
    {        
        $I->wantTo('create new user by name');
        $I->haveStub($user = Stub::makeEmptyExcept('User', 'create'));
        $I->haveStub($invalid_user = Stub::makeEmptyExcept('User', 'create', array(
            'validate' => function () { throw new Exception("invalid"); }
        )));     

        $user->setName('davert');

        $I->executeTestedMethodOn($user);

        $I->expect('user is validated and saved')   
            ->seePropertyEquals($user, 'role', 'member')
            ->seeMethodInvoked($user, 'validate')
            ->seeMethodInvoked($user, 'save');
    
        $I->expect('exception is thrown for invalid user')
            ->executeTestedMethodOn($invalid_user)
            ->seeExceptionThrown('ValidationException','User is invalid');               
            
        $I->expect('exception is thrown while trying to create not new user')
            ->changeProperty($user,'isNew', false)
            ->executeTestedMethodOn($user)                      
            ->seeExceptionThrown('ModelException', "User already created");
    }
}
?>

By this test we have 100% covered the 'create' method with test and isolated its environment. As a bonus, we can improve our documentation by the text of this scenario. If we use DocBlox, we can set up Codeception plugin and generate documentation for User class 'create' method.

With this method I can create new users by name.

Declared Variables:
* $user1 (User)
* $user2 (User)

If I execute $user1->create()

I expect user is validated and saved
I will see property equals $user1, 'role', 'member'
I will see method invoked $user1, 'validate'
I will see method invoked $user1, 'save'

I expect exception is thrown for invalid user
If I execute $user2->create()
I will see exception thrown 'ValidationException', 'invalid'

I expect exception is thrown while trying to create not new user
I change property $user1, 'isNew', false
If I execute $user1->create()
I will see exeception thrown 'ModelException', 'User already created'

We can say that the 'create' method is fully described by this text.

Conclusion

What we've got by writing the test for the create method of user class? We've made sure that by using this method the user is always validated and saved when created. We've also made sure the default role is 'member'. Well, that's all. But that's all that 'create' function is doing.

For further reading on Codeception unit tests see our documentation.

In the next post we will simplify the model test by breaking some isolation rules. Subscribe to our RSS channel to stay in touch.

Codeception 1.0.4 Released. Behavior Driven Development.

$
0
0

This release brings a real behavior driven development to Codeception. Before that we talked about testing in BDD-style, but nothing about real development by behavior. There were just few changes made in code. More changes are coming to documentation.

Specifications

With Behavior Driven Development you start development of class by writing it's specifications. Specifications are written as methods of Cest class and start with 'should' word.

<?php

class EventMachineCest {

    $class = 'EventMachine';
    
    function shouldHaveInitialState() {}   
    function shouldMoveBetweenTransitions() {}
    function shouldMoveBetweenTransitionsOnCondition() {}
}
?>

The EventMachine class in example above is not written, but we've already defined what to expect from it. After a basic requirements are specified we can take a deeper look into it and describe how it should be used. From this point your specifications become a valid Codeception tests.

<?php
class EventMachineCest  {

    $class = 'EventMachine';

   /**
   * @doc getState
   */
    function shouldHaveInitialState(CodeGuy $I)
    {
        $em = new EventMachine;
        $I->executeMethod($em, 'getState')
            ->seeResultEquals('initial');
    }
}
?>

For full EventMachineCest example see my Gist on Github.

Codeception generates a pretty good documentation with DocBlox based on your scenario. The @doc annotation marks that a getState method documentation will be updated by current test scenario.

I want to have initial state

I execute method $eventMachine, 'getState'
I see result equals 'initial'

Scenarios

For making acceptnace tests usable for writing Stories we've added 2 new methods. It's am and lookForwardTo which represent 'As a ...' and 'So that' definitions from Story.

<?php
$I = new WebGuy();
$I->am('regular site user');        // As a regular user
$I->wantTo('create my blog page');  // I want to create my blog page
$I->lookForwardTo('get a cool blog here');  // So that I get a cool blog

$I->expect("blog can't be created twice");
$I->expect("blog has RSS feed");
$I->expect("am administrator of this blog");
?>

After that Cept can be extended in a valid Cept file. Refer to this Gist demonstrates for example.

Bugfixes

  • seeLink and dontSeeLink for acceptance tests were fixed. Thanks to Kanstantsin Kamkou.
  • comments are displayed in output as well as actions.
  • Selenium docs updated.

Please update your version via PEAR:

$ pear install codeception/Codeception

or download updated Phar package.

Codeception 1.0.5 Released.

$
0
0

Almost every week Codeception gets a new release. I think it's quite good tempo. Every release contains not only bugfixes but a new features too. I'm satisfied but today's release, because all changes were made by new Codeception contributors. Thank you, guys!

Features

A new module for Social Engine was created by Artem Kovradin. He took the code of Zend Framework module and adopted it for Social Engine, which is build with powered by Zend Framework. With now on, you can simply test you social networks built on top of Social Engine.

Bugfixes

  • Windows command line problem solved, thanks to Morf
  • There were problem in functional tests for forms with no submits ('<input type="submit"'). This bug was pointed by svsool.

Also there were some encoding issues, but they are solved easily if you make sure your code and site has a UTF-8 encoding.

Thanks again to all contributors and reporters.

Please update your version via PEAR:

$ pear install codeception/Codeception

or download updated Phar package.


Codeception 1.0.7 Released.

$
0
0

That was quite a long time after last version was released. This time we decided to skip version 1.0.6, just because 1.0.7 looks prettier.

With this release Codeception can be used in CI systems like Jenkins. It's very easy: you just append '--xml' option for running test and receive xml report in JUnit format stored in 'tests/_log' directory. Other popular formats like Json and TAP were added too. Here is a sample report.xml generated by Codeception test suite:

<?xml version="1.0" encoding="UTF-8"?>
<testsuites>
  <testsuite name="acceptance" tests="9" assertions="29" failures="0" errors="0" time="41.532108">
    <testcase file="Cli\BuildCept.php" name="test build command (Cli\BuildCept.php)" assertions="5" time="4.016982"/>
    <testcase file="Cli\GenerateCeptCept.php" name="generate sample cept (Cli\GenerateCeptCept.php)" assertions="5" time="15.401255"/>
    <testcase file="Cli\GenerateCestCept.php" name="generate sample cest (Cli\GenerateCestCept.php)" assertions="3" time="3.742880"/>
    <testcase file="Cli\GenerateScenariosCept.php" name="generate scenarios (Cli\GenerateScenariosCept.php)" assertions="3" time="3.668740"/>
    <testcase file="Cli\GenerateSuiteCept.php" name="generate sample suite (Cli\GenerateSuiteCept.php)" assertions="4" time="4.706381"/>
    <testcase file="Cli\RunWithHtmlCept.php" name="check xml reports (Cli\RunWithHtmlCept.php)" assertions="1" time="2.428402"/>
    <testcase file="Cli\RunWithJsonCept.php" name="check json reports (Cli\RunWithJsonCept.php)" assertions="2" time="2.692029"/>
    <testcase file="Cli\RunWithTapCept.php" name="check tap reports (Cli\RunWithTapCept.php)" assertions="2" time="2.459026"/>
    <testcase file="Cli\RunWithXmlCept.php" name="check xml reports (Cli\RunWithXmlCept.php)" assertions="4" time="2.416413"/>
  </testsuite>
</testsuites>

Currently this reports are not perfect as for different file formats and you may lack some important information. For this cases, please create issues on GitHub or in Q&A section.

Thanks to Nikita Groshin new module for Kohana Framework integration was added. Please, check it out for your Kohana projects and leave a feedback.

Bugfixes

Also there were some encoding issues, but they are solved easily if you make sure your code and site has a UTF-8 encoding.

Thanks again to all contributors and reporters.

Please update your version via PEAR:

$ pear install codeception/Codeception

or download updated Phar package.

Also you should update Mink, as it uses Zend Framework 2 beta 3 now for PHP browser. All Codeception dependencies can be updated with a single command.

$ codecept install

Codeception 1.0.8 Released.

$
0
0

From this release you can install Codeception via Composer. If you have fucked up with PEAR it's a good idea to try out brand new Composer. It allows you to install Codeception with all it's dependencies, even PHPUnit, without any usage of PEAR.

If you already use Composer add this lines int your composer.json to and update packages.

    "require": {
        "Codeception/Codeception": "*"
    },
    "repositories": {
        "behat/mink-deps": {
            "type": "composer",
            "url":  "behat.org"
        }
    }

From now on you can run Codeception with

php vendor/bin/codecept

If you are new to composer but you are troubled with PEAR, the installation guide is updated for you.

Except this significant (but simple change) this release is all about bugfixing.

With the help of GitHub users ilex and nike-17 Kohana module was improved. Do you want to have a module for other frameworks? Maybe Yii, Fuel, CodeIgniter or Zend Framework 2? It's really simple. You just need to write a proper connector and you can go with performing functional tests inside your application. Check the [Functional Testing]http://codeception.com/docs/05-FunctionalTests) section of documentation.

And some good news about documentation! Jon Phipps has done a great job on editing the docs. Soon it will be published here. I know my English is not perfect. So I really appreciate any help in editing and reviewing documentation or blog posts.

Thanks to Sergii Grebeniuk for a small patch on autoloading.

There was not too much unique features in this release. Maybe you have some ideas on what should be improved?

New Codeception. Zombies and More.

$
0
0

This evening I released Codeception 1.0.9. The most important thing you may notice is documentation. It's just better. It was improved by Jon Phipps. Better phrasing goes to better understanding, right? But let's move on to see the actual new features.

Zombies are coming!

Two new modules were intoduced by Alexander Bogdanov @synchrone. It's new Selenium2 module and ZombieJS.

Ok, you may know about Selenium. But what is the purpose of Zombie?

Tools like ZombieJS, (PhantomJS, and more) are built in order to run tests without a browser. And so they are called headless. They don't require a browser window to start, they don't show any interactions on screen.

Why do we need browser for testing web applications? Only browser-based javascript engines can run all the client side code. ZombieJS is one of them, taken from browser and produced as a standalone tool. It's built with Node.js and requires Node.js, NPM, a C++ compiler and Python to install. Check out it's official site for more information.

Thanks to Mink from now on you can write ZombieJS tests inside Codeception just like tests for other cases.

Don't run too fast!

Selenium and Selenium2 modules was updated with the new delay option. If Selenium performs actions faster the user, and javascript just can't catch it it, you can slow down the execution by setting the delay param. It's set in milliseconds and will perform pauses after each step in scenarios.

Composer Tricks

Seems like the PHP WebScrapper Goutte (which is used by PHPBroser module) has a new backend now. It has moved from Zend Framework 2 libraries to new lightweight HTTP client Guzzle. So, no more Zend dependencies and long stack trackes. This change doesn't affect PEAR users, cause this change arrive in PEAR packages yet.

Thanks again to all contributors and reporters.

Please update Codeception version via PEAR:

$ pear install codeception/Codeception

or via Composer

$ php composer.phar update

Test WebServices With Codeception

$
0
0

Codeception testing framework got significant improvements during last week. The first and the major one is that you don't even need PEAR and Composer to execute tests. Only one file codecept.phar required. This might save your time and mind of your testers.

So Installation is much simplier now:

  1. Download archive.

  2. Execute it with PHP php codecept.phar

Now you can start generating a test suite with php codecept.phar bootstrap or execute existing tests with php codecept.phar run.

Documentation section was created. New section Reference was added. There you can review Codeception commands and configuration values.

But the most cool stuff is new module for testing web services!

Modules for SOAP and REST were added recently. You know it's always hard to test the API manually. So why not to automate it?

This API modules keeps simple manner in describing tests. Take a look at sample REST test.

<?php
$I = new ApiGuy($scenario);
$I->wantTo('create a new user by API');
$I->amHttpAuthenticated('davert','123456');
$I->haveHttpHeader('Content-Type','application/x-www-form-urlencoded');
$I->sendPOST('/users', array('name' => 'davert' ));
$I->seeResponseCodeIs(200);
$I->seeResponseIsJson();
$I->seeResponseContainsJson(array('result' => 'ok'));

And here goes a sample SOAP test:

<?php
use \Codeception\Utils\Soap;

$I = new ApiGuy($scenario);
$I->wantTo('create a new user thorough API');
$I->haveSoapHeader('Auth', array('token' => '123123'));
$I->sendSoapRequest('CreateUser', Soap::request()
    ->User
        ->Name->val('davert')->parent()
        ->Email->val('davert@codeception.com');
);
$I->seeSoapResponseIncludes(Soap::response()->result->val(1));

Ok, the one thing you may have noticed. We are working with JSON in first case and XML in second. But there is no JSON or XML in code! Well, we could have used it, but we didn't. Just because we can use PHP to set data in this formats. Json is built from PHP arrays and for XML is used jQuery-like styled XMLBuilder class. But you could possibly add a raw json or XMl into your tests. No problems with that!

Modules themselves are already documented and tested. Soon a complete guide on WebService API testing will be added.

The other thing worth to mention is new finalizers in test scenarios. If you need to execute code after test is finished and you don't want to put it in helper use the $scenario->finilize method. See it's usage example in new Manual Cleanup section of Guides.

This is Codeception 1.0.11. Download new version to run tests or update

via PEAR

$ pear install codeception/Codeception

or via Composer

$ php composer.phar update

1.0.14 - Custom Assertions In Helpers

$
0
0

Hi, that's been a while from the last release. But still Codeception is evolving. And today's release notes I'm going to start with some thoughts on Codeception installation strategy.

For a long time a PEAR was the primary method for install. It had some issues and develoeprs got stuck with it. Nowdays alternative is a [Composer[(http://packagist.org)] which Codeception uses too. But nevertheless we consider it a bit complex too. Codeception is tool where everything is kept simple. We are trying to make it work even for junior developers and testers. So our primary goal is to provide a standalone version 'codecept.phar' which was introduced recently. In future version we will try to make it autoupdate itself (as Composer does).

It's really cool cause it simplifies integration with CI systems and has less requirements to your PHP environment. Right now Codeception phar archive includes Symfony Components, Mink, PHPUnit in one file. So if you ever wanted to run PHPUnit tests without PEAR, the Codeception can be used that way too.

The major feature is related to current installation strategy. We finally added custom assertions to modules and user helper classes. Before that you should have used PHPUnit's static methods for assertions. But now you can just write this->assertXXX in a helper class.

In next example we connect PhpBrowser module to helper and use assertion to check a menu exists for current user.

<?php
class WebHelper extends \Codeception\Module {

    function seeEditingToolsMenu()
    {
        $content = $this->getModule('PhpBrowser')->session->getPage()->getContent();
        $this->assertContains('<a id="menu" href="#">Edit Post</a>',$content);
    }

}
?>

The Helpers section in Guides was totally rewritten to represent this change and provide more examples.

In this release a new module WebDebug was intorduced. It provides means to make screenshots with a single command. In case a screenshot can't be saved, it tries at least save the HTML response to file. After the test you can review all saved files to see what actually happened during test.

Thanks to Andrey Popov for contributions.

Bugfixes

  • click method for frameworks now accepts CSS selectors.

This is Codeception 1.0.14. Download new version to run tests or update

via PEAR

$ pear install codeception/Codeception

or via Composer

$ php composer.phar update

Major Codeception Update

$
0
0

Hi, last week Codeception got it's first major update. Welcome the Codeception 1.1. Many core classes were refactored to solve the common issues and reduce the level of dark magic inside. Only white magic left. And that's really cool 'cause you don't need to study to source code to implement your custom hooks now. Codeception is rapidly evolving to be the professional testing tool, ready to use by testers and developers through out the PHP world.

Test Execution Remastered

Did you ever were wondered why you can't receive values in test and pass it to next steps? To do something like this:

<?php
$user_name = $I->grabTextFrom('#user_name');
$I->fillField('username', $user_name);
?>

Actually, there is no any good reason for not doing so. The only reason was - the code was not designed to execute test file in runtime. The steps were recorded, analyzed, and only then they were executed, without touching the test file again. That is the source of dark magic that was removed in Codeception 1.1. This magic was awful because you didn't control the test execution. So, usage of custom PHP code in test was leading to unpredictable results. Even simple tasks was encouraged to be done in helpers, not in test code itself, to be run properly.

So what changed in Codeception 1.1? There is no magic in test execution, test file is required and executed, that's all. Still the analyzes step is not skipped, so test is run two times: first to record scenario, validate and analyze all steps, second to execute them. With that simple idea you can use ANY php code in your tests if only you define the stage when it should be executed. The additional bootstrap files should be loaded one time before the analyses:

<?php
if ($scenario->preload()) {
    require '_user_fixtures.php';
}
$I = new WebGuy($scenario);
$I->loginAs($user);
// ...
?>

And when you need something to be executed in runtime, like cleaning the fixture data, please use the following:

<?php
// ..
$I->loginAs($user);
$I->see('Hello, '.$user->name);
if ($scenario->running()) {
    $user->delete();
}
?>

In this example user is removed in the very end of scenario. $scenario->running method allows you to execute any code in the runtime. But please, always specify the stage when the custom code should be executed, or it will be executed 2 times.

In Codeception 1.0.x the build command was optional, when updating configuration. But now it's required to run every time the modules are added or removed in suite config file. That's the only new issue, but Guy-classes look much better now.

Grabbers

As the result of changed described above, you can finally return values to scenario and use them in next steps. The new grabbers commands were introduced:

<?php
$text = $I->grabTextFrom($element);
$value = $I->grabValueFrom($form_field);
$attr = $I->grabAttributeFrom($element, 'attribute');

$name = $I->grabFromDatabase('users', 'name', array('id' => 1));
// ....
?>

You can write your own grabbers. Just return values from your helper methods and you can use them in test. Please review the modules to see new commands there!

XPath Introduction

Codeception is a tool for testing, and many testers like specifying locators by XPath. CSS selectors have their limitations, so why not to use XPath in tests too? Sure, why not! You can freely use XPath selectors in your tests from now. But no new methods added for this! Really. The old methods were updated to support CSS and XPath as well. So whenever you need to pass a selector you can either pass CSS or XPath and Codeception is smart enough to guess what did you pass and how to use it.

<?php
$I->click('New User');
$I->click('#user_1 .user_new');
$I->click("descendant::*[@id = 'user_1']/descendant::a");
?>

All the methods where CSS was used were updated to support XPath. Try it!

Unit Tests

There was no common idea how to deal with unit tests in Codeception. As you know, Codeception can run standard PHPUnit tests as well as the hybrid scenario-driven unit tests. Scenario driven tests for many cases looked to complex to use. But they allowed to use Codeception modules in them. Why not to provide standard PHPUnit tests to use Codeception features? For Codeception 1.1 the new chapter of Guides describing unit tests is written. In brief: you can use the CodeGuy class inside your tests! Include any modules and use it as you need it. Use them to perform database cleanups, use them to check values in database, use them to work with file system. They are just wonderful helpers in your work.

And yep, new unit tests can be generated by command: generate:test.

Bugfixes and Minor changes

  • nested array logging was done by tiger-seo
  • ability to specify different configs for test execution, also done by (tiger-seo)
  • ZF1 module fixes by insside

Upgrade notes.

  • right after updating Codeception please run the build command.
  • remove all chained method executions in your tests. The $I object can return values, not self.

Codeception 1.1 can be downloaded from site,

via PEAR

$ pear install codeception/Codeception

or via Composer

$ php composer.phar update

P.S. Documentation was updated for 1.1 version.

Codeception with AMQP and Memcached

$
0
0

Good news, everyone! Codeception 1.1.2 released. And it's hard to list everything that were improved and fixed, but i will try. With the help of our active contributor tiger.seo Codeception got an AMQP module wich allows to manipulate queue engines, like RabbitMQ. You can use this module if you need to clear queues between tests. Also, new Memcache module was introduced. You can perform simple checks and use data from your Memcache storage in tests. Guys, it's very simple to contribute to Codeception. All new modules are welcome, they can grow from your local helpers and become part of this library. Just fork Codeception, add a module and send me a pull request!

UX Improvements

You should regenerate your guy-classes after this update with the build command. Rebuilt Guy-classes will contain full documentation for each method and link to the source code of underlying method. Also, with the help of tiger.seo Codeception got better PHPStorm integration. Codeception when run in PHPStorm console outputs stack traces that is recognized by PHPStorm. So you can click on any file name and move to it in IDE.

Save Scenarios as HTML

You know that there is --html option which saves results of running tests in HTML. But now you can save the test scenarios in HTML without running them. That's quite useful if you want to save test scenarios into your company's wiki. The HTML format can inserted into Confluence, for example. And now testers, managers, and developers will have the test scenarios up to date. Yep, thanks again to tiger.seo.

PEAR Updates

PEAR package was completely redesigned. Codeception is not using PEAR as a dependency manager anymore, Composer is ok. But PEAR is quite useful if you want a system-wide install, and simple call to Codeception with codecept command. PEAR package now contains all dependent modules and doesn't require PHPUnit or Mink installed anymore. That will prevent possible conflicts and reduce level of PEAR-related wtfs.

Bugs Fixed

Codeception 1.1.2 can be downloaded from site,

via PEAR

$ pear install codeception/Codeception

or via Composer

$ php composer.phar update

YetAnotherRelease.

$
0
0

Codeception 1.1.3 and then 1.1.4 was released during last month. In this post I will summarize the changes happened in this minor updates. The 1.1.3 version fixed one bug pointed by Nastya Ahramenko. Yep, only one bug. But it was pretty cool for me to mention it and make a release for it.

Nastya wrote:

If the web-page contains two similar links, then the second link is not opened. For example:

  1. Page contains two links: "Test Link" is first link, "Test" is second link
  2. Create test with the following steps
<?php
$I->click('Test Link');
$I->click('Test');

Both steps open the first link.

Actually we can discuss if it's a bug or a feature. But, it's more bug then a feature. This occur due to XPath locators in Mink and BrowserKit libraries. Codeception is a wrapper for Mink and BrowserKit, so there is no reason why it can't be done right. So, Codeception is solving this bug by seraching the strictly matched object at first, and then is trying to find it by more complex XPath locator. I.e., at first it will try to locate <a href="#">Test</a> and if it's not found will match the <a href="#">Test Link</a>.

That's all about 1.1.3

And now what about 1.1.4?

There are pretty much fixes from other contributors. Thanks for anyone sending me pull requests and patches. Here are the changes done by this awesome guys!

Selenium2 module improvements

Define Actions Beforehand

From now on it's much easier to define actions in helpers. You can write a method that is not defined yet, and then run new analyze command to append new commands to helper classes. It's quite useful when tester writes a test and needs some new actions to define. When you run

php codecept.phar analyze suitename`

you will be notified on all methods which do not exist in modules, and you will be asked to create them in helpers. Just try!

New Locator class

XPath locators are very powerful but are pretty hard to write and maintain. We decided to provide some useful functions to help writing locators better. Try new Codeception\Util\Locator for that. It will be described in next blogpost. Stay in touch.

As usual, Codeception 1.1.4 can be downloaded from site,

installed via PEAR

$ pear install codeception/Codeception

or via Composer

$ php composer.phar update

The Locator Class

$
0
0

In the latest Codeception 1.1.4 new Locator class was introduced. Basically it should simplify your life in writing complex XPath or CSS locators. Right now it has minimal, yet useful functionality.

Combine

Locator can combine two locators using OR operand:

<?php
use \Codeception\Util\Locator;

$I->see('Title', Locator::combine('h1','h2','h3'));
?>

This will search for Title text in either h1, h2, or h3 tag. You can also combine CSS selector with XPath locator:

<?php
use \Codeception\Util\Locator;

$I->fillField(Locator::combine('form input[type=text]','//form/textarea[2]'), 'qwerty');
?>

As a result the Locator will produce a mixed XPath value that will be used in fillField action.

tabIndex

Do you often use the TAB key to navigate through the web page? How do your site respond to this navigation? You could try to match elements by their tab position using tabIndex method of Locator class.

<?php
use \Codeception\Util\Locator;

$I->fillField(Locator::tabIndex(1), 'davert');
$I->fillField(Locator::tabIndex(2) , 'qwerty');
$I->click('Login');
?>

href

Does the page contain link wo specified URL? Check that easily with href method of Locator class.

<?php
use \Codeception\Util\Locator;

$I->see('Log In', Locator::href('/login.php'));
?>

And that's all folks for today. We are sure the locator class will evolve to simplify writing complex locators. If you have ideas what methods should be added, post them here. Or, which is better, patch this class and send Pull Request to Github.

5 Reasons to Try Codeception

$
0
0

Codeception is PHP framework for testing web applications in BDD-style. It was started about a year ago, as a plugin for symfony1, to speed up and simplify functional testing inside the framework. But as time passed, Codeception evolved to standalone project, with support of various frameworks and engines. It's built on top of wonderful PHPUnit, but with aim for acceptance, and functional scenario driven tests. In this post we will remind why you may like Codeception and why we feel it's awesome.

1. PHP!

Yes, the first reason is PHP. If you are PHP developer it's natural you would like to write tests in PHP. Codeception provides you the best way to do so. Any IDE with code completion and syntax highlighting will help you write tests faster and without stupid syntax mistakes. Usage of PHP inside of tests unleashes the true power and control over the test flow. You can use your application classes or create testing helpers. Also you can get values (with grabbers) from results and use them in your tests. You just control everything. And yep, use everything you like from PHPUnit.

<?php
$I = new TestGuy($scenario);
$I->wantTo('launch missiles from my website');
$I->amOnPage('/launch');
$I->click('Launch Missiles!')
$I->see('Missiles launched');
?>

2. Simplicity

You know, KISS is our first principle. Even Codeception requires basic knowledge of PHP it narrows testing to using PHP DSL where all actions are defined with user's perspective. Just enter the $I-> and select action from a list and put parameters. That's how a test is written. Also add minimal configuration in YAML format, and installation by downloading a single phar archive. It's really that simple.

codecept

3. Multi-Framework and Multi-Backend

You decided to migrate your application from symfony1 to Symfony2, from Kohana to Zend? You decided to test with Selenium inside a real browser? Your tests will run inside chosen the engine, no matters what happen. Codeception using one common syntax for all the backends. Frameworks support allows you to create more complex assertion and check the internals of your application, not only the visible part.

4. Complex Tests

Here comes a QA and says: I need XPath, I need complex selectors, I need to test UI elements strictly. No problems! You can use CSS selectors, XPath locators and even combine them with Locator class. You can also test your SOAP and REST webservices, pragmatical use XMLs (defined in jQuery-like style) and JSONs (as PHP arrays). Despite Codeception tend to be simple, it can be used by QAs creating solid tests automation platform.

<?php
$I->click('New User');
$I->click('#user_1 .user_new');
$I->click('//*[@id = 'user_1']/descendant::a');
$I->see('Title', Locator::combine('h1','h2','h3'));
$I->fillField(Locator::tabIndex(1), 'davert');
$I->see('Log In', Locator::href('/login.php'));
?>

5. Data

Tests isolation is a problem. Most of testing frameworks puts it's solving to your shoulders. But Codeception tries to fetch your needs and provide Data cleanup from the box. With the Db module you can repopulate database (MySQL, PostgreSQL, ...), after each run, use SQLite (for faster testing), or just run all tests inside transaction (in functional or unit testing). Also Codeception have modules for using and cleaning Memcache and AMQP storages.

And Finally!

And just to mention, the results of tests are readable to non-technical guys. When you export result in HTML you will see the cool colored page with all passed steps described in pure English. Also test results are readable to robots: export result as XML and the CI-server (Jenkins, Bamboo) will use them.

If you are still deciding weather or not to test your application, start doing it now. And Codeception is the right tool for this.

Error Reporting and XmlRPC

$
0
0

It looks like a good time for the new release! Do you agree?

And yes, there are enough changes to announce Codeception 1.1.5. In this release we concentrated mostly on fixing bugs and improving error reporting. But the most important change, that from now Codeception uses PHPUnit 3.7. This PHPUnit version doesn't have that much BC breaks as previous one, so we hope you will not notice this change.

Some tasty features were added too. But let's start with error reporting.

  • In stack trace PHP files of yours will be highlighted (if you use colors, of cource)
  • No more ERROR with no descriptions, every error have stack trace and description
  • Errors are displayed better, stack traces avaible only with --debug options

XML-RPC Module

Tiger SEO added just another useful module for testing XML-RPC web services. It requires 'php_xmlrpc' extension and PhpBrowser module to run. With this module you can perform XMLRPC calls and check the responses. You can review the code at GitHub or read the docs.

Minor Features and Bugfixes

  • Composer package fixed
  • grabServiceFromContainer method added to Symfony2 module
  • REST fixes and improvements by tiger-seo
  • Fix for using seeInDatabase command with PostgreSQL
  • build command is not generating methods with the same names anymore
  • no need to run build command just after bootstrap

BC breaks to aware of

There could be some BC breaks, you should know about. Before 1.1.5 you could start writing tests without defining a page. Codeception opened the root url "/" by default. So all actions were performed on home page. But opening the page before each test is not the best idea, especially if we test REST/SOAP web service. We just spend time for useless action. So whenever you write acceptance test, please start it with amOnPage action. This change didn't affect the functional tests (for now).

<?php 
$I = new WebGuy($scenario);
$I->amOnPage('/'); // required!
?>

Also, we did some changes for 2-steps tests loading, intrudoced in 1.1. At the first stage we read the test contents, in the next we execute it. From now on this stages are isolated, variables from preload will not pass to run. This will require loading of bootstrap file two times. Be prepared for that and optimize your bootstrap file.

As usual, Codeception 1.1.5 can be downloaded from site,

installed via PEAR

$ pear install codeception/Codeception

or via Composer

$ php composer.phar update

ProTips in Managing UI

$
0
0

Hi, we've decided to start a pro tips post series on Codeception. We hadn't too much time recently, because of the work on our startup Bugira, and the release of community-driven catalog oj Javascript libraries - Jster. You should definitely visit Jster (and add it to bookmarks), as it contains more then 800 javascript libraries for any needs in frontend development. But finally, We can get back to Codeception and tell about it's best usage practices.

Tip 1: Variables for UI elements

You can write pretty complex tests using Codeception. When you have lots of them you may find that changing page UI elements can lead to refactoring all the tests. If you plan to develop a solid automation platform for your web application, consider putting all UI elements into the variables. In this case you can modify your tests pretty easy. If you see like you are creating too much tests, you should think on reorganizing them in a way that can act stable despite of changes in project. It's really hard, features, designs, can constantly change and affect tests. But it's possible to keep your tests stable if you use variables instead of raw values in tests.

Let's say we have an acceptance test tests/acceptance/CreateTaskCept.php:

<?php
$I = new WebGuy($scenario);
$I->wantTo('create todo task');
$I->amOnPage('/tasks');
$I->fillField('New Task','Update a blog');
$I->click('Add');
$I->see('Update a blog', '#tasks');
?>

What if we change the name of buttons and the DOM position of the element where "Update a blog" text should appear? Let's move this elements to a _bootstrap file and push them into variables.

In tests/acceptance/_bootstrap.php:

<?php
$task_add_button = 'Add';
$task_new_field = 'New Task';
$tasks_list = '#tasks';
?>

And in tests/acceptance/CreateTaskCept.php:

<?php
$I = new WebGuy($scenario);
$I->wantTo('create todo task');
$I->amOnPage('/tasks');
$I->fillField($task_fill_field,'Update a blog');
$I->click($task_add_button);
$I->see('Update a blog', $tasks_list);
?>

As you see replacing values with variables shouldn't affect the test readability while you choose proper names for UI elements. We can also recommend to store user names, passwords, etc in bootstrap too. It will be automatically included on each test run. Use it.

Tip 2: Use PageObject

The PageObject is a pattern very popular among QA automation professionals. PageObject allows us to organize variables from a previous tip in more structured way. Instead of using raw variables we will group them into a class and use them in test and helpers. But classes and constants can't be added to _bootstrap, because bootstrap will be loaded before each test, so it will trigger an error: "Fatal: Cannot redeclare class". Let's deal with that by creating a new PHP file for TodoTask page class:

In tests/acceptance/_todoTaskPage.php:

<?php
class TodoTaskPage {
    const URL = '/tasks';

    static $add_button = 'Add';
    static $new_field = 'New Task';
    static $list = '#tasks';   
}
?>

Let's add it to tests/acceptance/_bootstrap.php:

<?php
require_once '_todoTaskPage.php';
?>

In this case you won't get lost in where which UI element is located. Because in PageObject pattern the UI element is bound to a page, which we defined by the URL property. And here is the updated test:

<?php
$I = new WebGuy($scenario);
$I->wantTo('create todo task');
$I->amOnPage(TodoTaskPage::URL);
$I->fillField(TodoTaskPage::$new_field,'Update a blog');
$I->click(TodoTaskPage::$add_button);
$I->see('Update a blog', TodoTaskPage::$list);
?>

After this update we have all the UI elements for todo task page kept in one place. Using and IDE you can easily find the right element and insert it into any test of your suite. Despite the raw variables classes and constants are accessible in helpers and unit tests. Also you can improve the page object classes with PHP's OOP power. If you are using PHP 5.4 you can include global UI elements (menus, breadcrumbs) with traits.

Lets create a trait for menu component in tests/acceptance/_menu.php:

<?php
trait GlobalMenu {
    public static $global_menu = "//div[@id=menu]";

    public static function menuItem($index)
    {
        return self::$global_menu.'/ul/['.$index.']';
    }
}
?>

We add it to tests/acceptance/_bootstrap.php:

<?php
require_once '_menu.php';
require_once '_todoTaskPage.php';
?>

And we are using it in previously declared TodoTaskPage:

<?php
class TodoTaskPage {

    use GlobalMenu;

    const URL = '/tasks';

    static $add_button = 'Add';
    static $new_field = 'New Task';
    static $list = '#tasks';   
}
?>

And now we can use properties and methods of a trait included in class. Thus, TodoTaskPage, as any class that uses GlobalMenu trait can access a menu. Let's write a new test for checking that menu contains a button to create a task.

<?php
$I = new WebGuy($scenario);
$I->wantTo('check task creation link is in a menu');
$I->amOnPage(TodoTaskPage::URL);
$I->see('Create Task', TodoTaskPage::menuItem(3));
?>

If you think on layout components as a traits and pages as classes, you can reorganize your UI elements in a very flexible way. Changes in markup or texts won't affect a tests, as you can easily update all the tests that rely on that element. You can even teach your template developer to update the corresponding PageObject each time she changes template.

Conclusion

Codeception is simple, yet powerful tool for test automation. If you plan to use test automation for the enterprise level projects, it's better to start with proper organization. As we think on architecture before writing the first line of code, we should think on scalable architecture of tests platform. Using PageObject and variables can dramatically improve the reusability (and keep KISS and DRY principles) of your tests.

Viewing all 321 articles
Browse latest View live




Latest Images