Please help Kenji Suzuki and Mat Whitney by spreading the word about this book on Twitter. If you don't have it, you can imagine that writing test code will be very difficult or cumbersome. After reading a tutorial for PHPUnit, I thought, "How do I test my application?" I struggled to see the similarities between the tests in the tutorial and the tests I would have to write for my own application.
Of course, you will be able to write test code for any PHP application after reading this book, but the focus will be on web applications. I use simple and easy to understand solutions first in the book so you don't get lost. This should give you an idea of what's ahead, or serve as a starting point if you want to find a particular piece of content to review later.
What is Automated Testing?
Primitive Example
Why should you write test code?
Finding the Middle Way
What should you test?
TDD or Not TDD
Setting Up the Testing Environment
Installing CodeIgniter
Installing ci-phpunit-test
Installing PHPUnit
Installing via Composer
Test Jargon
Testing levels
Testing Types
Code Coverage
Fixtures
Test Doubles
PHPUnit Basics
Running PHPUnit
Running PHPUnit via Web Browser
Configuring PHPUnit
Understanding the Basics by Testing Libraries
Testing a Simple MVC Application
Functional Testing for Controller
If you access the pages http/views/home, CodeIgniter calls the views() method of the Pages controller and passes it as the first argument. Since we modified the default_controller value to 'pages/view', if you access http CodeIgniter calls the Pagescontroller'sview() method without passing any arguments. So if you access http about, CodeIgniter calls the Pages controller'sview() method and passes "about" as the first argument.
First, we create the test case class in a file located at application/tests/controllers/Pages_- test.php. The $this->request() method in ci-phpunit-test is a method to test the controller. When using $this->request() you can use $this->assertResponseCode() method in ci-phpunit test.
Send a request to/ and check if the response output contains
Home
. Send a request to/about and check if the response output containsAbout
.Database Testing for Models
Unit Testing for Models
Why Should You Test Models First?
PHPUnit Mock Objects
Testing Models without Database
With the Database or Without the Database?
Testing Controllers
Why is Testing Controllers Difficult?
Test Case for the News Controller
Mocking Models
Authentication and Redirection
What if My Controller Needs Something Else?
Unit Testing CLI Controllers
Dbfixture Controller
Faking is_cli()
Testing exit()
Testing Exceptions
Testing Output
Monkey Patching
Checking Code Coverage
Testing REST Controllers
Installing CodeIgniter Rest Server
Testing GET Requests
Adding Request Headers
Testing POST Requests
Testing JSON Requests
Testing DELETE Requests
Browser Testing with Codeception
Installing and Configuring Codeception
Codeception is a PHP testing framework that offers three levels of testing: acceptance tests, functional tests, and unit tests. We need a module for our framework to use functional tests, but we don't have a module for CodeIgniter. In the previous chapters, we used PHPUnit with ci-phpunit-test, which provides the integration of the framework with CodeIgniter.
Since we don't have framework integration for Codeception, we'll be using Codeception alone, which should simplify the process of learning to use it for acceptance testing. Download the latest version (in this book we use v2.1.4) from http://codeception.com/install and place the downloaded codecept.pharin in the root directory of your PHP project. When installed via Composer, use vendor/bin/codecept instead of php codecept.pharin for the remaining instructions in this chapter.
Selenium is a project that automates browsers consisting of three parts: WebDriver, Server and Client. Selenium WebDriver is a driver to manipulate a browser. Selenium Server is a Java server application that communicates with Selenium client (in our case, facebook /webdriver¹in Codeception) and Selenium WebDriver. In summary, Codeception acts as our Selenium client and uses the Selenium Server to control the browser(s) used in our tests. In this book, we only use Codeception for acceptance testing, so all test case files are placed in the tests/acceptance directory.
In short, remove the red lines starting with - from the original file and add the green lines starting with + to get the new file.
Writing Tests
We should always use the line “$I = new AcceptanceTester($scenario);” write at the top of the test code. The rest of the test opens /, and checks whether the page received in the response contains the stringHome.
Running Tests
Browser Testing: Pros and Cons
Database Fixtures
We could generate an SQL dump file, but migrations and seeders have many benefits of their own, as discussed in Chapter 5. Since we already have the migrations, the seeders, and the ability to run them, we should use them here . also. We use the Dbfixture controller, which we tested in Chapter 8, and run the controller before running the acceptance tests.
If we do it this way, we don't have to maintain a SQL dump file and we make good use of our existing testing infrastructure. This handler checks to make sure it is being run from the CLI, and theall() method runs migrations and runs all seeder files that have the suffix Seeder.phpin theapplication/database/seeder directory.
Test Case for the News Controller
Set the URI with the $I->amOnPage() method and check the result with the $I->see() method. The $I->amGoingTo() method allows you to describe the actions you will perform. You can also use the $I->expect() and $I->expectTo() methods to add comments describing the expected results.
We can use the second argument to specify a CSS class that we expect to be applied to the string. We use the $I->fillField() method to fill in the fields in the form, then use the $I->click() method to click the submit button. If you want to know more about the functionality of Codeception's acceptance tests, see the Acceptance Test Documentation⁷.
Testing with Google Chrome
Testimonials: If you've enjoyed this book and don't mind leaving a short testimonial to be used in various places (eg the book's webpage), please leave a comment on this page². If you have slow tests, they can prevent you from testing, so your tests should be fast. But if you keep writing tests, you can end up with so many tests that it will take a long time to run your entire test suite, no matter how fast the individual tests may be.
Disabling Xdebug will make your test slightly faster than with Xdebug and the --no-coverage option. If you use SQLite, you can improve the performance of your tests by switching to an in-memory SQLite database. If you are using Query Builder and not using database-specific functionality, it will be possible to switch your application's database to SQLite for testing.
If you want to customize or improve ci-phpunit-test, read its source code. You can see the replaced version of it i_ci_phpunit_test/replacement/core/CodeIgniter.php. Some CodeIgniter classes and functions are replaced by ci-phpunit-test to make writing tests easier.
³https://github.com/kenjis/ci-phpunit-test/blob/master/docs/HowToWriteTests.md#can-and-cant. In another example of replacing classes to provide behavior only needed for testing, set_status_-header() is replaced to allow it to function when run from the CLI, and to store the status code in the CI_Output object , which gives ci-phpunit-test better access to the information. The set_is_cli() function allows ci-phpunit-test to change the return value of CodeIgniter's sis_cli() function.
If you pass a URI string to $this->request(), the CIPPHPUnitTestRequest object resolves the route using the CIPPHPUnitTestRouter object. After ciphpunit-test v0.10.1 it will also be used to set global variables for the CodeIgniter core objects. This is set by a class alias found in the_ci_phpunit_test/alias folder.
Congratulations