Skip to content
zenmiu edited this page Aug 17, 2011 · 6 revisions

Overview

To test LiteCommerce, use PHPUnit (http://www.phpunit.de) and Selenium (http://seleniumhq.org/) The PHPUnit files are not stored in the LiteCommerce repository; they are to be deployed separately (see the section on preparing the environment).

The tests are located in the .dev/tests directory:

  • .dev/tests/Classes - unit tests
  • .dev/tests/Web - Selenium tests for the frontend Ecommerce CMS interface (i.e. LC3+Drupal7 assemblies) and LC3 administrator interface
  • .dev/tests/Deploy - Selenium test installations for Ecommerce CMS

Additional files:

  • .dev/tests/FakeClass - classes that inherit certain LC classes and extend them by giving them modified properties. Unit tests use those classes for testing certain use cases
  • .dev/tests/PHPUnit - extensions for PHPUnit classes
  • .dev/tests/AllTests.php - script for preparing the list of tests
  • .dev/tests/local-*.php - samtest configuration example scripts
  • .dev/phpunit - PHP script for launching PHPUnit
  • .dev/phpunit.sh - unix shell script for launching testing. Calls .dev/phpunit with certain parameters
  • .dev/phpunit.bat - analog of .dev/phpunit.sh for Windows
  • .dev/phpunit-report.sh and.dev/phpunit-report.bat - respective analogs for phpunit.sh and phpunit.bat, which in addition to running the test generate a code coverage report.

LC3 Unit tests

Unit tests are made primarily for testing model classes (classes/XLite/Model), model repositories (classes/XLite/Model/Repo) and core classes (classes/XLite/Core), as well as model classes, brought in by modules. Controller and widget classes are tested primarily by Selenium tests.

Unit tests check the performance of all class methods via calling public methods (including model methods, automatically generated by Doctrin).

Tests are created in the subdirectories of .dev/tests/Classes, maintaining the structure of the class directories. In other words, the class src/classes/XLite/Model/Repo/Product.php will be tested by the test described in .dev/tests/Classes/Model/Repo/Product.php

A test class is named as the XLite_Tests_ prefix followed by the path to the test class file, where the directory name delimiter is underscore. Example: the file .dev/tests/Classes/Model/Repo/Product.php contains class XLite_Tests_Model_Repo_Product. The tests are inherited from class XLite_Tests_TestCase.

The simplest methods can be tested several at a time in a separate testing method (e.g., testing a model’s set and get methods can be carried out in testCreate()), but the main rule is that for each public method there is a unique test method. A test method begins with the test prefix, i.e. if class XLite\Model\Repo\Order has public methods findAll and findById, its test class XLite_Tests_Model_Repo_Order must include tests testFindAll and testFindById.

PHPUnit allows calling special methods prior to and after launching each test - setUp() and tearDown(). They can be used for setting up and restoring the test environment.

If in a test class we define a property:

protected $makeSqlBackupOnFailure = true;

Upon an unsuccessful completion of the test, an SQL dump of the database for the moment of the failure will be created in src/var/log/. This could be helpful in some cases when debugging the text.

Ecommerce CMS (Drupal+LC3) Selenium tests

Overview

Selenium tests check the functioning of an application as a completed system, via user interface. That means hitting the buttons, clicking on the links and watching whether it results in the action that was expected. Does that item appear? Does the redirect work? Where does it bring you? Is it the place where you needed to go in this case? Ideally, for each use case you should have tests that would check all the possible ways that use case could develop.

The purpose of writing such tests is to check the performance capacity of controllers and widgets.

Selenium tests, made for testing Ecommerce CMS, also assume that Drupal runs with the lc3_clean theme. They will fail to properly work with other themes.

Everything written for LC3 module tests is also true for Selenium tests, with the following reservations:

  1. The tests are located in .dev/tests/Web/<Interface Area: Customer или Admin>/
  2. Test class name prefix - XLite_Web_
  3. Directories with tests follow the functional classification of interfaces, not directories (i.e. tests/Web/Customer, tests/Web/Admin)
  4. Test classes are inherited from XLite_Web_AWeb or from an abstract test class of an interface area (like XLite_Web_Customer_ACustomer)
  5. A test class has its own check methods and control methods; see http://www.phpunit.de/manual/3.5/en/selenium.html#selenium.seleniumtestcase and http://seleniumhq.org/docs/04_selenese_commands.html. The complete list of commands is available here: http://www.cs.trincoll.edu/~aalcorn/phpdoc/docbuilder/vmdoc/PHPUnit/PHPUnit_Extensions_SeleniumTestCase.html http://release.seleniumhq.org/selenium-core/1.0.1/reference.html
  6. In addition to the Selenium methods, there is a list of auxiliary methods, defined in class .dev/tests/PHPUnit/SeleniumTestCase.php:
  • getJSExpression(expression) - calls a javascript expression in the contest of the window being tested and returns the result. Remember that the value will be passed as text. Therefore, instead of true you should expect a text string with the word ‘true’
  • assertJqueryPresent(pattern, message) - asserts that the specified jquery-pattern exists
  • assertJqueryNotPresent(pattern, message) - asserts that the specified jquery-pattern DOES NOT exist
  • validate() - validates current page for compliance with the HTML and CSS standards
  • getHTML() - gets current HTML as is
  • typeKeys() - overrides the default typeKeys() - ensures that the action properly generates all events in the browser
  • toggleByJquery() - toggles, enables and disables the check box with the calls for the required events
  • waitInlineProgress() - waits until an element with the single-progress-mark class linked to the specified form element appears and then until it disappears
  • assertInputErrorPresent() - asserts that the specified form element contains errors
  • assertInputErrorNotPresent() - asserts that the specified form element DOES NOT contain errors
  • dragAndDropDelay() - emulates drag-n-drop with calls for all events in the browser. Forcedly implemented via a third, intermediate element. Supports delays
  • waitForLocalCondition() - expects a specified condition in the context of the browser being tested

Upon an unsuccessful completion of the test, a log with a description of the error and backtrace will be created in src/var/log/. It could be used for tracing the place where the error occurs.

Examples of commands

Complete a form field:

$this->typeKeys(<form element selector>, <value>);

Submit form:

$this->submitAndWait(<form selector>);

Click element (including following a link):

$this->clickAndWait(<element/link selector>);

Get element text by its jquery selector:

$text = $this->getJSExpression(‘jQuery("<selector>”).html()’);

Get hyperlink URL by its jquery selector:

$url = $this->getJSExpression(‘jQuery(“<selector>”).attr(‘href’)’);

Get element attribute value:

$value = $this->getJSExpression("jQuery('<selector>’).attr('<attribute>')");

Get URL of page Selenium is currently looking at:

$url = $this->getLocation();

Open category page:

$url = \XLite\Core\Converter::buildURL(‘category’, ‘’, array(‘category_id’ => $id));
$this->open($url);

Wait until element appears on the screen:

$this->waitForLocalCondition(“jQuery(‘<element selector>:visible').length > 0”)

Preparing environment

Preparing Selenium

1. Installing Selenium server

Download the file like selenium-server-standalone-2*.jar (get the latest version) here:

http://code.google.com/p/selenium/downloads/list

Copy it to any place you like. Run it by typing the command:

java -jar имя-файла

2. Creating Firefox profile

Here is a detailed guide on doing that:

http://girliemangalo.wordpress.com/2009/02/05/creating-firefox-profile-for-your-selenium-rc-tests/

3. Configuring https exceptions

Run Firefox with the profile you have just created:

firefox.exe -P <profile name>

Go to the tab Settings -> Advanced -> Encryption -> View certificates -> Servers Click the Add exception button, enter the URL with the exception (first of all, that’s the URL of the website you are going to test), save the certificate permanently.

4. Checking availability of Selenium server

Run the server by typing the command:

java -jar server-server-standalone.jar  -interactive -firefoxProfileTemplate <path to profile>

In the console window that appears, enter:

cmd=getNewBrowserSession&1=*firefox&2=<Tested website URL>

Example:

cmd=getNewBrowserSession&1=*firefox C:\Program Files (x86)\Mozilla Firefox\firefox.exe&2=http://localhost/xlite_cms/

This opens a Firefox window (or, actually, two windows: one with the command log, and the working window).

Enter:

cmd=open&1=<Tested website URL>

Example:

cmd=open&1=http://localhost/xlite_cms/store/main

This opens the website page in the working window.

Now, try to open the website via the https protocol (enter the https address in the browser), make sure that no warning messages appear.

If everything is fine, the Selenium server is properly set up and ready. For your convenience, you can create a shortcut on the desktop to quickly launch Selenium in the future:

java -jar server-server-standalone.jar -firefoxProfileTemplate <path to profile>

Preparing PHPUnit

To be able to run the tests, you will need the PHPUnit library version 3.5. You can get it from PEAR or deploy it from GitHub.

Installing from PEAR (http://www.phpunit.de/manual/current/en/installation.html)

Update the local Pear:

pear channel-discover pear.phpunit.de
pear channel-discover components.ez.no
pear channel-discover pear.symfony-project.com
pear channel-update pear.php.net
pear upgrade --alldeps

Install the latest PHPUnit and its extensions:

pear install --alldeps --force phpunit/dbunit
pear install --alldeps --force phpunit/file_iterator
pear install --alldeps --force phpunit/text_template
pear install --alldeps --force phpunit/php_codecoverage
pear install --alldeps --force phpunit/php_tokenstream
pear install --alldeps --force phpunit/php_timer
pear install --alldeps --force phpunit/phpunit_mockobject
pear install --alldeps --force phpunit/phpunit_selenium
pear install --alldeps --force phpunit/phpunit

Installing from GitHub (http://www.phpunit.de/)

Cloning:

mkdir phpunit && cd phpunit
git clone git://github.com/sebastianbergmann/phpunit.git
git clone git://github.com/sebastianbergmann/dbunit.git
git clone git://github.com/sebastianbergmann/php-file-iterator.git
git clone git://github.com/sebastianbergmann/php-text-template.git
git clone git://github.com/sebastianbergmann/php-code-coverage.git
git clone git://github.com/sebastianbergmann/php-token-stream.git
git clone git://github.com/sebastianbergmann/php-timer.git
git clone git://github.com/sebastianbergmann/phpunit-mock-objects.git
git clone git://github.com/sebastianbergmann/phpunit-selenium.git

Checking out version 3.5:

cd phpunit && git checkout 3.5 && cd ..
cd dbunit && git checkout 1.0 && cd ..
cd php-file-iterator && git checkout 1.2 && cd ..
cd php-code-coverage && git checkout 1.0 && cd ..
cd php-token-stream && git checkout 1.0 && cd ..
cd phpunit-mock-objects && git checkout 1.0 && cd ..
cd phpunit-selenium && git checkout 1.0 && cd ..

Here is a shell script that will help you to quickly update GitHub repositories in the future:

#!/bin/sh

# Update current branches of all repositories from GitHub

echo "Updating repositories from GitHub"

for i in `find . -type d -depth 1`; do echo -n "$i..."; cd $i; git branch | grep "*..." | sed  's/* //'; git pull -q; cd ..; done

Configuring tests

Copy the file .dev/tests/local-sample.php to .dev/tests/local.php and assign your environment values to the constants. When testing, you may need to use test accounts with payment systems, credentials for accessing the mail boxand other data of the private nature. You are highy discouraged to keep that data in the repository to prevent the possibility of committing that data by an accident. Create a file xlite-tests.config.php, place it somewhere beyond your working repository, and set the path to it in .dev/tests/local.php:

// Directory where xlite-tests.config.php is located
define('XLITE_DEV_CONFIG_DIR', 'c:\\Dev\\etc');

The constant TEST_DEPLOYMENT_MODE in .dev/tests/local.php sets the deployment mode for Selenium tests. To test the installation (DEPLOY_DRUPAL), you will need the distribution kit - deploy it anywhere you like (e.g., in xlite/build/src) and set this constant to 1. The URL and file system path to the location with the deployed distribution kit is to be specified in the constants SELENIUM_SOURCE_URL and DRUPAL_SITE_PATH in the body of the condition if (1 === TEST_DEPLOYMENT_MODE).

To run other Selenium tests, set the TEST_DEPLOYMENT_MODE constant to 0.

Other than that, the DEPLOY_DRUPAL mode requires a config file .dev/build/config.local.php with access to the database.

Running tests

The tests are run from the console. To run the tests, use the following scripts:

.dev/phpunit.sh - run tests
.dev/phpunit-report.sh - run tests and generate coverage report

and the Windows analogs:

.dev/phpunit.bat
.dev/phpunit-report.bat

Examples of running tests (parameters are the same for both phpunit and phpunit-report):

./phpunit.sh - run all tests
./phpunit.sh Core/Auth - run tests from the Core/Auth class
./phpunit.sh Core/Auth:login - run one specific test
./phpunit.sh NOWEB - run unit tests only, no selenium tests
./phpunit.sh ONLYWEB - run selenium tests only, no unit tests
./phpunit.sh DEPLOY_DRUPAL - run the installation script test for the Drupal+LC assembly

Upon the completion of the tests, phpunit-report.sh generates a coverage report for the directory xlite/coverage

Errors that occur during testing are recorded in the respective logs: <path to tested xlite>/var/log
Errors that occur during selenium tests are recorded in the respective files named as selenium.20110328-131211.backtrace.
Clone this wiki locally