© 2015 X2Engine Inc.

Difference between revisions of "Testing With PHPUnit"

From X2Engine
Jump to: navigation, search
(What are tests?)
(What are tests?)
Line 15: Line 15:
 
: For tests involving communication with a MySQL database, especially if that communication involves a change in any data.
 
: For tests involving communication with a MySQL database, especially if that communication involves a change in any data.
 
;WebTestCase (extends [[yii:CWebTestCase|CWebTestCase]])
 
;WebTestCase (extends [[yii:CWebTestCase|CWebTestCase]])
: For tests that involve web browser actions.
+
: For tests that can involve web browser actions and change in the persistent data of the web app.
 
[[File:TestCase.png|400px|thumb|right|Anatomy of a typical test case]]
 
[[File:TestCase.png|400px|thumb|right|Anatomy of a typical test case]]
  

Revision as of 01:21, 30 January 2013

This page covers development using unit and functional tests to develop components and extensions to X2CRM. While not all of X2CRM has been built using test-driven development, some tools and structure have been set up for performing it when developing new features. All automated tests in X2CRM use PHPUnit, and in the case of functional testing, Selenium. To understand more what these tools are, why it is important to know about them and how they will strengthen your design and development methodology (in addition to helping you make your code more stable), the following is recommended reading:


Introduction

What are tests?

Tests are organized into PHP classes called test cases that are stored within protected/tests/unit (unit tests) or protected/tests/functional (functional tests). Test cases extend one of the following classes:

CTestCase
For ordinary, non-databse unit tests; useful for defining expected behaviors of component classes that don't rely on tables or data that is specific to a HTTP request
CDbTestCase
For tests involving communication with a MySQL database, especially if that communication involves a change in any data.
WebTestCase (extends CWebTestCase)
For tests that can involve web browser actions and change in the persistent data of the web app.
Anatomy of a typical test case

Running test cases

Running a test case proceeds as follows: on the server where the testing environment is installed, inside of the protected/tests folder, run
phpunit path/to/TestCase.php
or, to run a group of test cases that exist in the same directory:
phpunit directory/
PHPUnit will recursively scan directories for test cases to run.

Installation

For the most up-to-date information on how to install PHPUnit, see Chapter 3: Installing PHPUnit in the official PHPUnit manual. In addition to PHPUnit, you will need each of the following PHPUnit extensions:

  • DBUnit
  • PHP_Invoker
  • PHPUnit_Selenium
  • PHPUnit_Story

See the installation guide for more information on how to obtain these extensions.

Setting up a test database

A few very important points to note about tests involving a database connection:

  • A different database will be used than the live database
  • The contents of each of the test database's tables will be fixed at the beginning of each test using *fixtures*
  • All database records generated during tests or through manual interaction will be purged when fixtures for the table in question are used

After creating the test database, the following steps can be used to set it up for database testing:

  1. Copy the installer files back into the root of the web application: index.php, initialize.php, requirements.php, and initialize_pro.php if on professional edition.
  2. Re-run the installer, but enable "Testing Database".

Functional Testing with Selenium

An advanced PHPUnit/Selenium configuration involving multiple network hosts, operating systems and web browsers. PHPUnit (1) begins a test by starting browser sessions on a remote host running Selenium RC (2). Selenium then commands the web browsers to open the web application in testing mode (3) and run automated instructions, sending results back to PHPUnit (i.e. whether a test has passed or failed). All logos are © their respective owners.

Selenium provides the means to control and automate browser actions, and hence, to run tests with full browser sessions. If it is desired to automate in-browser tests with Selenium, the following conditions must be ensured:

  1. The <selenium> section in the configuration file protected/tests/phpunit.xml is set properly. For information on how to configure this, see The PHPUnit Manual Appendix C: The XML Configuration File
  2. Selenium RC on all the hosts defined in phpunit.xml can be accessed from the web server on the specified ports (note: if they are behind a firewall, it will be necessary to set up NAT in order to properly use them)
  3. The URL defined as constant TEST_BASE_URL in protected/tests/WebTestConfig.php resolves properly (points to index-test.php/ on the web server).
  4. PHPUnit and the necessary extensions are installed on the web server

Creating Selenium test cases

  1. Create a class that extends WebTestCase in protected/tests/functional
  2. Note that at the beginning of the execution of a test case's method, the method WebTestCase::setUp() will be called, and this will create a session as the admin user. If any additional operations are necessary to include at the beginning of every test, you may override the method, but should include a call to parent::setUp() at the beginning of it.
  3. In the test method, open the URL where the test is to begin by calling WebTestCase::openX2(), passing it as an argument the URI[[wikipedia:Uniform Resource Identifier]]: The part of a URL that identifies the resource on the server to be accessed. In the context of the API, this refers to the relative path within the web server based in the web root of X2Engine, i.e. ''index.php/api2/Contacts/324.json'' as opposed to the full URL, which begins with the protocol (i.e. "http") and might also contain a path relative to the web site's document root relative to the base URL (what would come after index-test.php).
  4. Note the availability of CWebTestCase's methods, especially those inherited from PHPUnit_Framework_TestCase, PHPUnit_Framework_Assert and PHPUnit_Extensions_SeleniumTestCase, in addition to WebTestCase::session() (which will ensure the session matches the user/password defined in WebTestCase::$login, logging the browser out/in as necessary) and the aforementioned methods that will be inherited from WebTestCase.

Using test cases built with Selenium IDE

Building functional tests involving browser automation with Selenium can be done with PHPUnit browser commands, i.e. assertTextPresent. However, it is far more easy, convenient and quick to build them using Selenium IDE. Selenium IDE is a web browser plugin for Firefox that provides a means of generating Selenium commands by capturing mouse and keyboard actions. It also allows you to edit and re-position commands after creating them, as well as boasting a host of other very useful features. To obtain Selenium IDE, visit the Selenium HQ downloads page.

To run a native Selenese .html test case created in Selenium IDE:

  1. Save the .html in the same folder as the PHP test case class (a subdirectory of protected/tests/functional)
  2. In a test method, open the URL where the Selenese test case is to begin using WebTestCase::openX2().
  3. Call the method WebTestCase::localSelenese() with the filename of the Selenese test case as the sole argument.

Selenium tests are easy to execute an arbitrary number of times; simply calling localSelenese() again will run the script a second time. Selenese test cases are thus optimal not only for typical tests due to how easy they are to generate, but also are good for tests that need to be repeated as different users with different permissions (in the case that similar behavior/display is desired for all sets of permissions).

Running Selenium tests

If the Selenium server(s) can be reached, run the test case the same way you would a unit test.