Difference between revisions of "Testing Joomla Extensions with Codeception"

From Joomla! Documentation

Line 196: Line 196:
 
</source>
 
</source>
  
It has sense because for readability sometimes you would prefer to see:
+
Instead of hardcoding the url in the test:
<source lang="php">
 
$I->amOnPage(JoomlaAdministratorNewBannerPage::$URL);
 
</source>
 
 
 
Than:
 
 
<source lang="php">
 
<source lang="php">
 
$I->amOnPage('/administrator/index.php?option=com_banners&view...');
 
$I->amOnPage('/administrator/index.php?option=com_banners&view...');
 
</source>  
 
</source>  
  
The first way is more readable for non developers. To have the benefit of both, the url and a representative name that describes the page where we are going, we will write the urls the following way:
+
The pros of this approach is:
 +
- first way is more readable for non developers.  
 +
- it helps to make tests more maintenable in the case of a url change in the system
 +
 
 +
However in joomla a change in an url is rare, and if it happens changing it will just be a Find&Replace task. I Joomla test we want to have the benefit of both, the url and a representative name that describes the page where we are going. That will make our tests more readable. Thus, we will write the urls the following way:
  
 
<source lang="php">
 
<source lang="php">

Revision as of 06:02, 27 March 2015

Note: this page is under construction

What is Codeception?[edit]

Codeception PHP Testing Framework is designed to work just out of the box. This means its installation requires minimal steps and no external dependencies preinstalled (except PHP, of course). Only one configuration step should be taken and you are ready to test your web application from an eye of actual user.

See the following video of codeception in action testing Joomla:

Codeception provides possibilities to do Unit Testing or to Test APIs, however this page is focused in System Testing.

Why Use Codeception?[edit]

Why use Codeception when we already have Selenium IDE?

Codeception works great with Selenium. But with Codeception you can write your tests in PHP. The main reason is: Selenium IDE tests are tightly bound to XPath locators. If you ever change anything in layout tests will fall. Codeception locators are more stable. You can use names, labels, button names and CSS to match elements on page.

Features

  • Selenium WebDriver integration
  • Elements matched by name, CSS, XPath
  • PageObjects and StepObjects included
  • Powered by PHPUnit
  • Data Cleanup
  • Parallel Execution of tests
  • BDD-style readable tests

Structure of a test[edit]

The testing framework is built on the three layered testing architecture

Scenarios (Cept Class)[edit]

Cept or Test, it is the main class which contains steps of execution for the tests, Cept Class will call Step Class functions which will indirectly make use of page objects to perform operations

Example:

$I = new AcceptanceTester($scenario);
$I->wantTo('Install Joomla CMS');
$I->amOnPage('http://localhost/installation/index.php');
// I Wait for the text Main Configuration, meaning that the page is loaded
$I->waitForText('Main Configuration', 10, 'h3');
$I->click(JoomlaInstallationConfigurationPage::$elements['Language Selector']);
$I->click(JoomlaInstallationConfigurationPage::$elements['English (United Kingdom)']);
$I->fillField('Site Name', 'weblinks');
$I->fillField('Description', 'Site for testing Weblinks component');
$I->fillField('Admin Email', $cfg['Admin email']);
$I->fillField('Admin Username', $cfg['username']);
$I->fillField('Admin Password', $cfg['password']);
$I->fillField('Confirm Admin Password', $cfg['password']);
$I->click('Next');
...

Page Objects[edit]

Each page on your application has a class which we call page objects, each page class will have information about the URL, fields, Text present on the page. We use the best possible selector for any field on the page.

Example[edit]

class JoomlaAdministratorLoginManagerPage
{
	/**
	 * @var string Url of the page
	 */
	public static $URL = '/administrator/index.php';

	/**
	 * Array of Page elements indexed by descriptive name or label
	 *
	 * @var array
	 */
	public static $elements = array(
		'username' => "#mod-login-username",
		'password' => "#mod-login-password"
	);
}

Naming convention for Page Objects[edit]

When this document is created Codeception 2.0 was not having a PSR-4 compatible autoloader. Therefore we are creating a convention so with the future Codeception 2.1 with PSR-4 compatible autoloader (https://github.com/Codeception/Codeception/pull/1228) we are creating a naming convention for Pages so it will cost us a small effort to move to autoloaded classes in the future.

The naming convention works as follows:

APPLICATION (for example Joomla, Patchtester, Weblinks or your Extension name)
+ CLIENT (in Joomla we use it for defining if is Installation, Administrator or Frontend
+ CLIENT PART (In Joomla we use it following the menu are were it belongs: Components, Menus, System,...)
+ PAGE NAME (The Page name) 
+ Page

Examples:

JoomlaAdministratorLoginPage
JoomlaAdministratorSystemGlobalconfigurationPage
JoomlaInstallationConfigurationPage

And they are located with a folder estructure similar to:

Folder estructure for Pages in System Tests


Remind that in Codeception 2.0 you need to specify each folder in the acceptance/_bootstrap.php file:

<?php
// Here you can initialize variables that will be available to your tests
\Codeception\Util\Autoload::registerSuffix('Page', __DIR__.DIRECTORY_SEPARATOR.'_pages/joomla/installation');
\Codeception\Util\Autoload::registerSuffix('Page', __DIR__.DIRECTORY_SEPARATOR.'_pages/joomla/administrator');

Documentation[edit]

More info: http://codeception.com/docs/07-AdvancedUsage#PageObjects

Step Objects[edit]

Step Objects are classes which contains steps which are to be executed on the application to perform certain operations, step objects make use of page objects to perform these actions.

Example:

class JoomlaAdministratorLoginSteps extends \AcceptanceTester
{
	/**
	 * Function to execute an Admin Login for Joomla 3
	 *
	 * @return void
	 */
	public function doAdministratorLogin($user, $password)
	{
		$I = $this;
		$I->amOnPage(\JoomlaAdministratorLoginPage::$URL);
		$I->fillField(\JoomlaAdministratorLoginPage::$elements['username'], $user);
		$I->fillField(\JoomlaAdministratorLoginPage::$elements['password'], $password);
		$I->click('Log in');
		$I->see('Category Manager');
	}
}

More info: http://codeception.com/docs/07-AdvancedUsage#StepObjects

Setting Up Codeception[edit]

setting up the repository[edit]

clone the directory

  1. Fork com_localise
  2. Git clone git@github.com:*your-github-profile-name*/com_localise.git

Testing with Codeception[edit]

There are two ways to get and run codeception, via PHAR or via Composer. Using Composer is recommended (because we are using in some tests the Codeception 2.1 development version not available in the composer.phar).

  • Using Composer
   You need to have Composer in your system, if not download it from here: https://getcomposer.org/
   Step 1: composer update
   Step 2: run Codeception by doing: php vendor/bin/codecept build
  • Codeception.phar
   Linux Machine  : wget http://codeception.com/codecept.phar
   Windows Machine: Download from codecept.phar
   Step1 : php ./codecept.phar build

Running the Test[edit]

Rename tests/acceptance.suite.dist.yml to tests/acceptance.suite.yml

Step 1: Modify the configuration at tests/acceptance.suite.yml to fit your server details.
Step 2: php codecept.phar run

with --steps to see a step-by-step report on the performed actions.

php vendor/bin/codecept run --steps

with --html. This command will run all tests for all suites, displaying the steps, and building HTML and XML reports. Reports will be store in tests/_output/ directory.

php vendor/bin/codecept run --html

To activate the debug mode in Codeception just add the parameter --debug when you run the tests:

php vendor/bin/codecept run acceptance --debug

Best Practices at Testing[edit]

How to use URLs[edit]

Codeception documentation suggests to use URL's as properties of a Page Object:

$I->amOnPage(JoomlaInstallationConfigurationPage::$URL);

Instead of hardcoding the url in the test:

$I->amOnPage('/administrator/index.php?option=com_banners&view...');

The pros of this approach is: - first way is more readable for non developers. - it helps to make tests more maintenable in the case of a url change in the system

However in joomla a change in an url is rare, and if it happens changing it will just be a Find&Replace task. I Joomla test we want to have the benefit of both, the url and a representative name that describes the page where we are going. That will make our tests more readable. Thus, we will write the urls the following way:

$I->amGoingTo('go to Create New Banner page at Joomla Administrator');
$I->amOnPage('/administrator/index.php?option=com_banners&view...');

When do not use contains[edit]

We do not recommend to use the function contains on XPath because is not specific and can create false positives at tests. See: https://github.com/joomla-projects/GSOC-Webdriver_system_tests_for_CMS/pull/99#issuecomment-69004191

Always add xPath locators to your tests[edit]

Performance in tests is very important. You can reduce dramatically the time spent on a test with just adding a few extra locators. For example, the following code pertains to a test:

// see($text, $selector = null)
$I->see('Your article has been published');

In the previous code we are not facilitating the "Selector" so Codeception will have to search for the element in all the HTML. Doing this instead:

$I->see('Your article has been published', '#messages');

the tests went from: Time: 1.17 minutes to: Time: 49.18 seconds

You can see this video of a real example: http://www.youtube.com/watch?v=0JCv0BR2yZY

Losing 30 seconds in every Assertion can delay your tests dramatically. Therefore, remind always to add xPath locators to all your Assertions.

Using locators in $I->see[edit]

Do not use see without locator:

// Wrong:
$I->see('Your article has been published');

// Right:
$I->see('Your article has been published', '#messages');

Using locators in $I->waitForText[edit]

Do not use waitForText without locator:

// Wrong:
$I->waitForText('Finalisation');

// Right:
$I->waitForText('Finalisation', 10, 'h3');

Quote and Double Quotes in Compex XPaths[edit]

Sometimes you will have to write XPaths that looks like:

//button[@onclick='Joomla.submitbutton("config.save.application.apply")']

When moved to a Page Object you will probably will face this situation:

Typical issue when you write a long XPath in a Page object

To avoid it remind to escape the quotes:

// Wrong
public static $elements = array(
   'Save' => "//button[@onclick="Joomla.submitbutton('config.save.application.apply')"]"
);
// Right
public static $elements = array(
   'Save' => "//button[@onclick=\"Joomla.submitbutton('config.save.application.apply')\"]"
);