Build PHP's YII framework and related test environment _php instance on Mac OS

Source: Internet
Author: User
Tags documentation dsn php language pear php script php website composer install yii

YII integrates unit testing and functional testing, using PHPUnit and selenium implementations. The author in the configuration process encountered a lot of trouble, record here.

Necessary Concepts
Selenium
Selenium is a well-known automated testing tool that can be used to automate test Web projects by adjusting the local browser to complete the test. Selenium is divided into server-side and client-side, server use Java development, so need a JDK, server at startup, will start an HTTP service, the client through HTTP communication with the server, to the server to launch test requests, the server will automatically adjust the browser to complete the test. Testers are responsible for writing client script, supporting most of the mainstream programming language, of course, this is due to the powerful power of the open source community, developed for different languages for Selenium interface program, server and client agreement between the author does not study, because it is not important.

PHPUnit
PHPUnit is a test framework and tool for the PHP language, using its framework for unit testing and the tools used to perform functional testing. Based on this test framework, someone has done the Selenium PHP interface program as an extension of phpunit.

How the YII framework integrates
Yii, based on PHPUnit, makes some simple encapsulation for the test. Therefore, it is necessary to rely on both when using Yii for testing.

Environment installation
Firefox
Selenium-server can identify a few browsers, it seems to be IE and Firefox, so on OS X first installed Firefox browser. Install the browser and the general software installation is not a big difference, here is not tired described.

Jdk
because Selenium-server is developed using Java, we need to install the JDK first, Baidu search JDK download installation can. No longer be tired of the statement.

Selenium-server
First, install the server version of selenium. Under OS X, Brew can be used for installation, which is more convenient:

$ Brew Install Selenium-server-standalone

Because the source of the Selenium-server is on the Googleapis, it is necessary to turn the wall to operate, in fact, if not over the wall, the other steps are more difficult.

The prompt after the installation is complete:

To have launchd start selenium-server-standalone at login:
  ln-sfv/usr/local/opt/selenium-server-standalone/*. Plist ~/library/launchagents
Then to load Selenium-server-standalone now:
  launchctl load ~/library/ Launchagents/homebrew.mxcl.selenium-server-standalone.plist
Or, if you don ' t want/need Launchctl, can just run:
  selenium-server-p 4444

It's clear from here that we start the service side with the following command

$ selenium-server-p 4444

As you can see, normally selenium-server listens on port 4444, and if you want to modify the port, then the corresponding YII office needs to modify the configuration.

PHPUnit
Detour
as a personal understanding, PHPUnit is a collection of tools and frameworks, tool-attribution tools, and frameworks. From the official website's documentation, PHPUnit's tools are released in the form of a Phar package, and the framework is managed by pear. So let's take a look at these two concepts first. Those who are not interested can skip this section.

Phar is a PHP packaging solution. That is, a PHP program or a PHP website can be packaged and distributed together, or even called as a function module. As a result, phpunit can fully package the tool into Phar, and when performing Phar, it is often necessary to use PHP commands.

$ wget https://phar.phpunit.de/phpunit.phar
$ chmod +x phpunit.phar
$ sudo mv phpunit.phar/usr/local/bin/ PHPUnit
$ phpunit--version
phpunit x.y.z by Sebastian Bergmann and contributors.

You can download the PHPUnit executable file with the above command, and you can see that this is a Phar package

Pear is a system of PHP extensions because early PHP reuse is difficult. The compiled language is easy to reuse because of its compact and rigorous grammar. and PHP because of flexibility, reuse up learning cost is high, so pear put forward a programming specification and distribution system to achieve PHP function reuse, it seems that pear has been replaced by composer (said below). But since the old things have gone a detour may wish to write down.

You can install pear in this way under the Mac:

$ wget http://pear.php.net/go-pear.phar
$ sudo php-d detect_unicode=0 Go-pear.phar

As you can see, Go-pear is also a Phar, except that it is a PHP script that installs pear, which can be executed using PHP commands. You will be prompted during installation to modify the php.ini file:

warning! The include_path defined in the currently used php.ini does don't
contain the PEAR php directory you just specified:
   
    </usr/share/pear>
If The specified directory
is also to the include_path used by your scripts Have problems getting any PEAR packages working.


Would to alter PHP.ini </ETC/PHP.INI>? [y/n]: Y

php.ini </etc/php.ini> include_path updated.

Current include path      :.:
configured directory      :/usr/share/pear
currently used php.ini (guess):/etc /php.ini
Press Enter to continue: the 

' pear ' command are now at your service at/usr/bin/pear

* * the ' pear ' command is isn't currently in your PATH, so need to
* * * use '/usr/bin/pear ' until you have added
* * '/usr/bin ' To your PATH environment variable.


   

From this tip we can learn:

Pear's executable program is installed in/usr/bin/pear
Pear has a working directory is/usr/share/pear, this working directory needs to be added to the php.ini, if the installer automatically add words, will be like this:

* * * * Added by Go-pear
include_path= ".:/ Usr/share/pear "
; * * * *

PHP actually searches for include_path, in addition to searching the current directory, when we use require and other functions that contain other files. This configuration indicates that the program code that is installed through pear will be stored in the working directory, and PHP will be able to find it, by default there is a system.php in the working directory, so the following code works:

<?php 
 require ' system.php ';
? >


using composer installation
Originally, PHPUnit can be installed through pear, however, the passage of time, in the composer of the era, PHPUnit also announced the full support composer, and give up pear, originally through the installation of pear is really not the way. Finally forced to, only on the composer (say Pack management tools really more than 10 fingers enough, in the future there is a chance to a horizontal comparison).

First install composer, in the state of the wall:

$ brew Update
$ brew tap josegonzalez/homebrew-php
$ brew tap homebrew/versions
$ brew Install php55-intl< c13/>$ Brew Install Josegonzalez/php/composer

So the composer is ready.

In the root directory of the project, create a Composer.json that writes:

{"
  Require-dev": {"
    phpunit/phpunit": "4.7.*",
    "Phpunit/php-invoker": "*",
    "Phpunit/dbunit": "> =1.2 ",
    " Phpunit/phpunit-selenium ":" >=1.2 ",
    " phpunit/phpunit-story ":" * "
  }
}

The above Phpunit-selenium is based on the PHPUnit written selenium client library, as detailed in the text of the reference.

Then, under the project root directory, execute the

$ sudo composer install

Composer will create a vendor directory in the root directory based on this Composer.json file and download all dependencies into this directory, where vendor/bin the phpunit executable file below.

Because it is a YII project, the CD to the/protected/tests directory, execute the following command to start the default sitetest.php test method: (note that before executing, keep selenium-server open)

$ .. /.. /vendor/bin/phpunit functional/sitetest.php

You will see that Firefox will start automatically during execution and output from the following log:

PHPUnit 4.7.7 by Sebastian Bergmann and contributors.
warning:deprecated configuration Setting "Selenium" used

.

time:11.52 seconds, MEMORY:6.50MB

OK (1 Test, 1 assertion)

The PHPUnit utility will automatically find the tests/ Phpunit.xml This configuration file and make some configurations based on this, and Yii uses the PHPUnit and Phpunit-selenium framework to communicate with the Selenium-server end, which launches the browser and returns the logs and results to the client. The whole process is roughly the same.

Test

Testing is an essential part of software development. Whether we realize it or not, we're always testing it when we're developing web apps. For example, when we write a class in PHP, we might use some injected echo or die statements to show whether we have implemented a method correctly; When we implement a Web page that contains a complex set of HTML forms, we might try to enter some test data to confirm that the page is interacting with what we expect. More advanced developers will write code to automate this test process, so whenever we need to test something, All we need to do is call the code and the rest is left to the computer. This is called automated testing and is the main topic of this chapter.

The test support provided by YII includes unit testing and functional testing.

Unit tests verify that a separate unit of the code works as expected. In object-oriented programming, the most basic unit of code is the class. Therefore, the primary responsibility of unit testing is to verify that every method of work implemented by this class is normal. Unit tests are usually written by someone who has developed this class.

Functional tests Verify that the feature is working as expected (e.g., submitting operations in a blog system). Functional testing is generally more advanced than unit testing because the features to be tested often involve multiple classes. Functional testing is usually written by people who are very knowledgeable about the requirements of the system. (This person can be either a developer or a quality engineer).

Test-driven development

The development cycle of the so-called test-driven development (TDD) is shown below:

    • Create a new test that covers the attributes you want to implement. The test is expected to fail at the first execution because the attribute is not yet implemented.
    • Perform all tests to ensure that the new test is unsuccessful.
    • Write code to make the test pass.
    • Perform all tests to ensure all tests pass.
    • Refactor the newly written code and make sure that the tests are still able to pass.
    • Repeat steps 1 through 5 to advance the implementation of the overall functionality.

Building a test environment

The test support provided by YII requires PHPUnit 3.5+ and Selenium remote control 1.0+. Please refer to the documentation they provided to install PHPUnit and Selenium remote control.

When we use the YIIC WebApp Console command to create a new YII application, it will generate the following files and directories for us to write and complete the test.

testdrive/
protected/contains protected application files
tests/contains the application test
The fixtures/contains data fixtures
functional/contains functional testing
The unit/contains unit tests
report/contains the coverage report.
bootstrap.php This script is executed at the beginning
Phpunit.xml phpunit configuration file
webtestcase.php web-based functionality Test base class
As shown above, our test code is mainly placed in the three directories of fixtures, functional and unit, and the report directory is used to store the generated code coverage reports.

We can perform tests (whether unit or functional) by executing the following commands in the console window:

% CD testdrive/protected/tests
% phpunit functional/posttest.php  //Perform a single test
% phpunit--verbose functional< c4/>//executes all tests under ' functional '
phpunit--coverage-html./report Unit

The last command above will execute all the tests under the Unit directory and generate a code-coverage report in the reports directory. Note to generate the Code-coverage report you must install and open the PHP xdebug extension.

The bootstrap script for the test

Let's see what's going on in the bootstrap.php file. First of all, this file is a little special because it looks like a portal script, and it's the portal where we perform a series of tests.

$yiit = ' path/to/yii/framework/yiit.php ';
$config =dirname (__file__). ' /.. /config/test.php ';
Require_once ($YIIT);
Require_once (DirName (__file__). /webtestcase.php ');
Yii::createwebapplication ($config);

As shown above, we first include the yiit.php file from the YII framework, which initializes some global constants and the necessary test base classes. Then we use the test.php configuration file to create an application instance. If you look at the test.php file, you'll find it inherits from Mai n.php This configuration file, except that it adds a fixture application component with a class named [Cdbfixturemanager].

Return Cmap::mergearray (
 require dirname (__file__). /main.php '),
 array ('
 components ' =>array ('
  fixture ' =>array ('
  class ' => ') System.test.CDbFixtureManager ',
  ),/
  * Remove the following comment to provide a database connection for the test.
  ' DB ' =>array (
  ' connectionString ' => ' DSN for test database ',
  ), '
  *)
;

When I perform those tests that involve database operations, we should provide a test-specific database so that test execution does not interfere with normal development or production activities. In this way, our paper needs to remove the comments on the DB configuration above, and then fill in the DSN (data source name) of the ConnectionString property to connect to the database.

With such a startup script, when we perform unit tests, we can get an application instance that is similar to the service requirement, and the main difference is that the test has a fixture manager and its own test database.

Define a specific state (fixtures)

Automated testing needs to be performed many times. To ensure that the testing process is repeatable, we want to test it in some knowable state, which we call a particular state. For example, test the article creation feature in a blog application, and each time we test, the table associated with the article (for example. Post table, Comment table) should be restored to a specific state. The PHPUnit document is a good description of the general construction of a particular state. This section mainly describes how to build a database-specific state like the example just described.

Setting the specific state of the build database is probably one of the most time-consuming parts of the application that tests the database for back-end support. The [Cbbfixturemanager] application components introduced in YII can effectively mitigate this problem. When you run a set of tests, it basically does the following things:

Before all tests run, it resets the test-related data to a knowable state.
Before a single test runs, it resets a specific table to a knowable state.
During the execution of a test method, it provides the access interface to the row data that is supplied to a particular state.
Use the [Cdbfixturemanager] that we configured in the application configuration as follows.

Return Array ('
 components ' =>array ('
 fixture ' =>array ('
  class ' => ') System.test.CDbFixtureManager ',
 ),)
;

Then we provide a specific state data under the directory protected/tests/fixtures. This directory can be specified as a different directory by configuring the [Cdbfixturemanager::basepath] attribute in the application configuration file. Specific state data is composed of multiple PHP files called specific state files. Each particular state file returns an array, Represents the initial row for a particular table of data. The file name is the same as the table name. The following is an example of storing specific state data for a Post table in a file named post.php.

<?php return
Array ('
 sample1 ' =>array ('
 title ' => ' test post 1 ',
 ' content ' => ' test post Content 1 ',
 ' createtime ' =>1230952187,
 ' Authorid ' =>1, '
 sample2 ' =>array (
 ' title ' = > ' Test post 2 ',
 ' content ' => ' test post Content 2 ',
 ' createtime ' =>1230952287,
 ' Authorid ' => 1,
 ),
);

As we can see, there are two rows of data returned. Each row represents an array whose key is the field name of the table, and its value is the corresponding field value. Each row's index is a string called a row alias (for example: Simple1, Simple2). Later, when we write a test script, we can easily invoke this line of data through its alias. You may have noticed that we did not specify the value of the ID field in the specified state above. This is because the ID field has been defined as the self-added primary key, and its value is automatically generated when we insert new data.

When [Cdbfixturemanager] is referenced for the first time, it will carefully examine all of the specific state files and then use them to reset the corresponding table. It resets the table by emptying the table, resetting the list of values for the table's primary key, and inserting data rows from a particular state file into the table.

Sometimes, we may not want to reset each table described in a particular state file before a set of tests, because it may take a lot of time to reset too many specific state files. In this case, we can write a PHP script to customize this initialization process. This should be saved in a directory that holds a specific state file. and named Init.php. When [Cdbfixturemanager] detects the existence of this script, it executes the script instead of resetting each table.

It is also possible to reset a table by default, such as emptying the table and inserting specific state data. If this is the case, we can write an initialization script for the specific state file specified. This script must be named +.init.php the table name. For example, the initialization script file for the Post table is Post.init.php. When [Cdbfixturemanager] discovers this script, it executes the script instead of resetting the table by default.

Tip: Too many specific state files extend the test time considerably. Therefore, you should only provide specific status files for tables where the data changes in the test. The tables that do the lookup service do not change, so no specific state files are required.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.