Integration Testing II - Installing MODX and Using Fixtures

Creating a test version of MODX and using it as a fixture in testing


In the previous article in this series, we looked at a simple example of integration testing using both our Validator and User classes.

In this one, we'll install the MODX CMS in preparation for some later articles on acceptance testing and working with larger platforms. We'll also see how to implement Codeception Fixtures.


MODX logo

This article assumes that you've installed and configured Codeception and PhpUnit and created the classes and unit tests described in the previous articles. The test files and classes are available at GitHub here.


The MODX CMS

If you're a regular visitor here, you probably already have a local MODX installation on your computer. For the purposes of testing, though, it's a good idea to have a completely separate, mostly empty install of MODX to use for testing. In these articles, we'll assume that the MODX site is in the test directory (so, on a localhost install, the site would be at localhost/test). Our database will also be called test and will have a user with full rights with these credentials:

Username: JoeTester
Password: TesterPassword;

We won't be using the database in our tests until the next article, but if you set it up with these credentials, it will make that easier.

MODX will attempt to create the database, its tables, and a db user for it during the MODX installation process, but it doesn't always work. If it doesn't, use PhpMyAdmin or the equivalent and set up a database called test and the user described above with full rights to it before running setup. Use utf-8 and utf8_general_ci for the character set and collation.


Installing MODX

Installing MODX is very straightforward for most people. It's just a matter of putting the files in place and running setup. There's a description of the basic install here, but here's how I like to do it:

Download the current version of MODX here. I recommend getting downloading the "Traditional" installation package.

Unzip the file somewhere, it will create a directory named for the version of MODX you downloaded. Go into that directory. You should see the core/ and manager directories, along with the index.php file. These are the files and directories that go at the root of your MODX site. If you were installing them on a remote site, you'd zip them up, transfer the .zip file, and extract them on your site's server.

Since most testing happens on a localhost install, you can just copy them all to the subdirectory where the site goes. This will be a directory called test in the web root of your server. In other words, if your server root is the htdocs directory, you'd create an htdocs/test/ directory and copy all the MODX files to it.

Note that the MODX install we've created will not be in the same directory as our tests. We want to keep it completely separate from the testing environment.


Creating the Database

MODX will attempt to create the database for you during setup, but I prefer to do it ahead of time to make sure setup runs smoothly and the character set and collation are set correctly.

Create a database called test with PhpMyAdmin or the equivalent. Important: select utf8 for the database character set (it's not the default) and utf8_general_ci for the collation. Create a database user named JoeTester with TesterPassword as the user's password. Be sure that user has full rights to the database.


Running Setup

With all the MODX files in place. Open your browser and enter this address (you may need to correct the server name):

localhost/test/setup

Follow the prompts, but be sure to change the character set to utf8 and the collation to utf8_general_ci. I'd also recommend changing the directory/file permissions to 755/644 unless you have a reason not to.

Give test for the name of the database. Use JoeTester for the both the database user and the MODX admin username. Use TesterPassword for both passwords. On a production site, this would be a bad practice, but since we'll only be using this site for testing, we might as well simplify things.

Leave everything else at its default value, but toward the end of the install, don't let Setup delete the setup directory yet. Keep it in place in case you need to rerun setup. Delete it once you're able to log into the MODX Manager and see the Dashboard. Leaving the setup directory in place is a security vulnerability.

Follow the prompts of the setup process until you see the login screen for the MODX Manager. There are several places where you'll need to scroll down to get to the next step.

At the end of the process, if you can log in (with the credentials JoeTester and TesterPassword) and see the dashboard and welcome message, the install has been successful.

The dashboard will give you some warnings about the core being accessible and the config file not being read-only. On a local install, you can ignore these as long as you have a working firewall.

Since this is an install that's strictly for testing, you don't need to do anything else to the install. It's not a bad idea to export the test database at this point, and back up all the files in the test directory, either by zipping them up and moving the .zip file somewhere safe, or using Git. That way you can restore the test site to its original condition by importing the .sql file and restoring the files.


Fixtures

I really hate the term Fixture. First and foremost, the word already had a meaning before being used for software testing — "a piece of equipment or furniture which is fixed in position in a building or vehicle." There are plumbing fixtures and light fixtures and everyone knows what they are. Surveillance cameras are fixtures. So are wall-mounted TVs and drinking fountains. None of these are remotely like software testing fixtures.

Worse yet, the term "fixture" in software testing has multiple definitions. Some people use the term to refer to the testing context in which your tests take place. In this usage (from Wikipedia), the fixture is the standardized environment you create to run the tests. You might, for example, create an empty database and insert a set of records into it for your tests to use. With this definition, the database is not the fixture, the *state* of the database is the fixture.

A second definition (also from Wikipedia) holds that the term "fixture" refers to the process (class or procedure) that creates the environment under which the tests run and restores things to their original state when the tests are finished. The process is referred to (not by me) as "the fixture of the test." In this definition, the fixture is the code that sets up the testing environment.

A third definition (from Ruby and Codeception) uses the term to refer to the sample data used in multiple tests (e.g., an array of data). The data providers we saw earlier in this series could be thought of as examples.

There is also a fourth definition (from Codeception and PhpUnit) under which "fixtures" refer to components of your testing environment that are shared across tests. This overlaps with some of the previous definitions and is the definition that's closest to what we're doing here.

In actual practice, the fixtures in Codeception are simply elements of the fixtures array. The elements of the fixtures array are usually set in the _bootstrap.php file and will be available in any tests in the suite that contains that _bootstrap.php file (or all suites, if it's the _bootstrap.php file in the same directory as the suite directories).

The fixtures array might look like this:

$fixtures = array(
    'max_users' => $maxUsers, // simple variable
    'core_path' => $corePath, // file path
    'modx' => $modx, // instance of a class
    'db' => $dbh, // database handle
    'users' => $users, // array holding user data
);

The "Fixtures" in the Fixtures array can be simple variables, database handles, variables that hold instantiated classes, arrays of sample data — anything that will go on the right side of a PHP associative array. Since there are other ways to set the values of simple variables, the Fixtures array tends to hold more complex objects like database handles and major classes. In the case of code running inside a platform like WordPress, Laravel, or MODX, the platform itself may be stored in the Fixtures array.

The Codeception Fixtures array is never accessed directly. Instead, you use methods like Fixtures::Add($key, $value) to add an element to the array and Fixtures::get($key) to retrieve it. There is also Fixtures::exists($key) to see if the element exists in the Fixtures array. If we weren't using Codeception, we'd likely create a Fixtures class to hold the array and implement those methods.


MODX as a Fixture

Some of the tests in upcoming articles use the MODX CMS platform. In MODX, the modX class (always represented by the $modx variable) contains many of the standard operations of MODX. That variable serves as a database handle as well as a collection of utility methods like sanitize(), setDebug(), getChildIds(), runProcessor(), makeUrl() etc.

The $modx object is fairly expensive to instantiate, so we definitely don't want to do it in each test we write. It makes sense to create a single instance of it to share among our tests and place that instance in the Fixtures array.

Caution: Using a shared fixture for a class or variable that you will be modifying during your tests is considered a bad practice. It can make your tests fragile and unreliable unless you re-initialize the fixture before each test and restore its original state at the end of all tests.


Using Codeception Fixtures

Codeception fixtures are a convenient way to share test elements across tests. To create them in _bootstrap.php, you need to have a _bootstrap.php file and an entry in the appropriate .yml file telling codeception what it's called.

You should already have a _bootstrap.php file in the _build/tests directory. That's the master file. It will run before tests in any suite. You can also have separate _bootstrap.php files inside any suite. They will execute after the master one, and before any tests in the suite. In other words, if the bootstrap file is in the Unit directory, the configuration statement goes in the unit.suite.yml file. In our example here, it goes in the integration.suite.yml file. In later versions of Codeception, the configuration line looks like this:

bootstrap:_bootstrap.php

In older versions, it takes this form:

settings:
    bootstrap: _bootstrap.php

Remember, we'll be using our $modx object in integration tests, so the line(s) above go in the integration.suite.yml file. Create it if it doesn't exist and add those lines to it.

The _bootstrap.php file itself goes in the _build/tests/integration directory and should contain this code (fix the path in the require statement):

<?php
use Codeception\Util\Fixtures;

require_once 'c:/xampp/htdocs/test/core/model/modx/modx.class.php';
echo "Getting MODX";
$modx = new modX();
$modx->getRequest();
$modx->getService('error', 'error.modError', '', '');
$modx->initialize('mgr');
Fixtures::add('modx', $modx);

The use statement at the top tells Codeception that we're going to be using the Fixtures array.

The echo "Getting MODX"; line is just there so you can make sure the _bootstrap.php file is executing. You should see that message in the console when running a test. It can be removed as soon as everything works.

The rest of the code, except the last line, instantiates the $modx object and prepares it for use in our tests.

The final line puts the $modx object into the fixtures array. In the array, the key is 'modx,' and the associated value is the $modx object itself.

When we need to use the $modx object in a test, we add the use Codeception\Util\Fixtures; line at the top, create a $modx class variable and do this:

$this->modx = Fixtures::get('modx');
assertTrue($this->modx instanceof modX);

Actually, creating MODX as a fixture should really go in the master _bootstrap.php file in the _build/tests directory. Although we didn't use the $modx object in any unit tests, it's likely that you'll need it eventually if you'll be testing code for MODX.

Feel free to move it there now. It, and your test code, should work as long as there's a reference to it in the codeception.yml file.

Now, we'll create the test file that will contain that code.


T7_FixtureTest.php

Run this command in the _build directory:

codecept generate:test integration T7_Fixture

Here's the code for the complete T7_FixtureTest.php file (also available at GitHub here):

<?php
use Codeception\Util\Fixtures;

class T7_FixtureTest extends \Codeception\Test\Unit
{
    /**  @var $tester IntegrationTester */
    protected $tester;

    /** @var modX $modx */
    public $modx;


    protected function _before()
    {
        $this->modx = Fixtures::get('modx');
        assertTrue($this->modx instanceof modX);
    }

    protected function _after()
    {

    }

    public function testWorking()
    {
        assertTrue(true);
        $docs = $this->modx->getCollection('modResource');
        assertNotEmpty($docs);
    }
}

This is a very simple test that just confirms that we've set up our $modx fixture correctly. Note the use statement at the top. That statement matches the one in the _bootstrap.php file we created earlier and allows the static Fixture::get('modx') call to work.

Remember that we put the $modx object into the Fixtures array in _bootstrap.php with Fixture::add('modx', $modx). Now, we're just asking for it by giving its key to Fixture::get().

After getting the $modx object in the _before() method, we test to make sure it's an instance of the modX class.

In the testWorking() method, we actually use the $modx object by calling its getCollection() method and test to make sure that the result is not empty. During setup, MODX creates a home page for you, so getCollection() will find it. It's not a bad idea to add this test just below the assertion in the testWorking() method:

assertCount(1, count($docs));

That will make sure that the site has only one resource and none have been left over from previous test runs.


Coming Up

In the next article, we'll take a look at using Codeception to test code that runs inside the MODX CMS.


For more information on how to use MODX to create a web site, see my web site Bob's Guides, or better yet, buy my book: MODX: The Official Guide.

Looking for high-quality, MODX-friendly hosting? As of May 2016, Bob's Guides is hosted at A2 hosting. (More information in the box below.)



Comments (0)


Please login to comment.

  (Login)