Programming With Yii2: Automated Testing With Codeception

Final product image
What You'll Be Creating

If you're asking, "What's Yii?" check out my earlier tutorial, Introduction to the Yii Framework, which reviews the benefits of Yii and includes an overview of what's new in Yii 2.0, released in October 2014.

In this Programming With Yii2 series, I'm guiding readers in use of the Yii2 Framework for PHP. In this tutorial, I'll explore automated testing using Codeception, which is integrated with the Yii2 development framework.

Admittedly, my experience writing tests with my code is scarce. I've often been part of solo or small projects with limited resources. During my time at Microsoft, we had distinct test teams that did this. But frankly, this is likely typical of you too, right? Programmers like to code, they don't write tests—at least old school programmers didn't.

Codeception is an innovative library that literally aims to make writing tests fun and easy. And, I'd say they've succeeded to a reasonable degree. As I dipped my toe into the water of "Lake Codeception", it was mostly easy and fun. However, as I began to go deeper, I ran into configuration issues with Yii and the specific modules used in this series. There were definitely challenges. Overall, though, I'm impressed and see the benefit of learning more.

Put simply, Codeception and its integration with Yii make me want to write more tests, a first for me. I suspect you'll have a similar experience. 

A little reminder before we get started, I do participate in the comment threads below. I'm especially interested if you have additional thoughts or want to suggest topics for future tutorials. If you have a question or topic suggestion, please post below. You can also reach me on Twitter @reifman directly.

Getting Started

Installing Codeception

To guide me, I used Yii's Testing Environment Setup documentation. I began with a global install of codeception so I could use it from any project.

You also need to require codeception/specify:

And codeception/verify:

Next, it helps to set up an alias for codecept using your global composer directory:

This sets the alias:

Yii also requires you install Faker, which generates fake testing data for your application:

Setting Up Codeception With Your Application

Codecept bootstrap initializes codeception for your Yii application, creating a variety of configuration files for building and running tests against your application. We're using the Hello application from this series for this tutorial. See the GitHub link on this page to get the code.

For some reason, I also ended up with duplicate testing directories in hello/tests; just deleting hello/tests/functional, hello/tests/acceptance, and hello/tests/unit cleared things up. All the tests live in hello/tests/codeception/*.

The Different Kinds of Tests

Codeception is focused on three kinds of tests:

  1. Unit testing verifies that specific units are working, such as an exhaustive test of all your model's methods.
  2. Functional testing verifies common application scenarios as if a user was acting them out, but using web browser emulation.
  3. Acceptance testing is identical to functional testing but actually runs the tests through a web browser.

And it supports three different kinds of test formats for your testing code:

  1. Cept: it's the simplest single scenario test file
  2. Cest: an object oriented format for running multiple tests within a single file
  3. Test: tests written on PHPUnit, a PHP testing framework

Let's begin with an example of acceptance tests using cept format:

Acceptance Testing

We'll use Codeception's Welcome test example first.

This generates tests/acceptance/WelcomeCept.php, which we'll edit below.

Since acceptance tests require the browser, we have to edit /tests/acceptance.suite.yml in our project to provide our development URL, http://localhost:8888/hello:

Now, we're ready to modify the initial test in tests/acceptance/WelcomeCept.php. I'm writing a test that loads the front page to make sure that it works as expected. 

Codeception tests have the concept of an actor, in this case, $I = new AcceptanceTester().

Here's how it describes actors in the Codeception documentation:

We have a UnitTester, who executes functions and tests the code. We also have a FunctionalTester, a qualified tester, who tests the application as a whole, with knowledge of its internals. And an AcceptanceTester, a user that works with our application through an interface that we provide.

You can comment your tests with code, such as $I->wantTo('perform a certain test') or 'ensure that the frontpage works'.

In my test, I want to see $I->see text for 'Congratulations!' and 'Yii-powered':

Here's the current Hello home page:

Programming with Yii - The Hello Home Page

Next, let's run the test, simply codecept run:

As you can see, our test passed, and the code to verify this functionality was quite readable and simple.

Notes on Yii's Default Tests

To go further, I began using Yii's default tests. At this point, I ran into a number of configuration issues—most due to my use of the custom yii2-user module in this series. Others were due to small bugs with Yii, which its team has been quick to respond to and fix when reported on GitHub; in some cases, issues had been fixed in later releases of the yii2-basic tree.

Also, because I'd updated the yii2-basic tree for this series, I had to make small changes to some of the default tests.

Here's an example of the output for running the default acceptance tests once I'd made some minor adjustments:

Functional Testing

To get functional tests to work, I needed to run an instance of Yii's built-in server. I hadn't known about this component until Yii's Alex Makarov mentioned it in our GitHub exchange.

I made small changes to the functional tests in /tests/codeception/functional, mostly to look for my specific updated text strings, i.e. "Invalid login or password" in place of Yii's default. Here's a look at LoginCept.php:

Basically, the code accesses the LoginForm model and tests its various methods using Yii serve.

Here's the /tests/codeception_pages/LoginPage.php testing code it's leveraging (I also had to modify it for changes we've made to the series):

You can see that we're coding the actor to fillFields and click buttons for our updated form fields. 

While troubleshooting my Codeception integration with Yii, I found it helpful to run these tests in verbose mode:

Here's the verbose output from the Login functional tests—in MacOS Terminal, PASSED and FAILED are color coded red or pink and inverted for visibility:

Overall, there's a bit to learn to get started with Codeception and properly code your tests. But the results are impressive and helpful.

Unit Testing

Basically, unit tests are programmatic testing of our infrastructure and models. Ideally, we would write tests for every method and usage variation of our models.

Unfortunately, I was not able to get unit tests to work within our tree because of either small Yii bugs yet to be released or configuration issues between Codeception and yii2-user which we integrated in How to Program With Yii2: Integrating User Registration

I'll address unit testing again in our Startup series which does not use yii2-user but instead uses the Yii Advanced tree's built-in user integration.

Let's look at a couple of examples from the Yii2-app-basic tree.

Testing Contact Form Emails

The hello/tests/codeception/unit/models/ContactFormTest.php tests sending an email through programmatic use of models:

I was unable to successfully get this test to pass because of a small bug in Yii which hasn't been updated yet (or at least I couldn't find the updated code). My drop of the Yii codebase was naming outbound email with date stamps and the code above was looking for a fixed filename. Thus, it always failed. Still, it's useful to see how programmatic testing can use models to generate a file and then look for that file and validate its contents to verify that code is working.

Testing Login

Let's look at hello/tests/codeception/unit/models/LoginFormTest.php. Again, my use of yii2-user made it overly difficult to integrate at the time of writing this tutorial; however, we can look at the conceptual approach to unit testing user model functions.

Here's testLoginCorrect(), which looks to see if login succeeds with a correct password:

It uses the LoginForm model to programmatically log in the user, and then it programmatically looks to see if Yii's current user is now no longer a guest.

What's Next?

I hope that you've enjoyed learning about Codeception and its integration with Yii, despite some of the roadblocks I ran into. Default installation of yii2-basic today should perform better.

If you'd like to read more about deciding when and what to test and why, I recommend reading Yii's Testing Overview. There's certainly more to learn about Codeception and writing more complete tests.

Watch for upcoming tutorials in our Programming With Yii2 series as we continue diving into different aspects of the framework. If you'd like to know when the next Yii2 tutorial arrives, follow me @reifman on Twitter or check my instructor page

You may also want to check out our Building Your Startup With PHP series, which is using Yii2's advanced template as we build a real-world application. In fact, you can try out the startup application, Meeting Planner, today.

Related Links

Tags:

Comments

Related Articles