<
Neerav Mehta
Founder & CEO
This post will help you write and run your first Drupal integration test using Red Test framework in less than 15 minutes. By end of this post, you will be able to write an automated test to make sure that superuser is able to create two pieces of content, one published and the other unpublished. We'll test that anonymous user is able to view the published content and is not able to view the unpublished content. You can follow along these steps on any Unix or Mac machine and have automated tests running in a matter of minutes.
Choose any Drupal 7 site that you have running on your machine.
Go through the Red Test installation post and install Red Test in this site. You can skip the last step in this post where we run the tests since the test suite that comes by default is the one meant for Standard installation profile of Drupal and will invariably fail with your custom site.
Create a new content type called "Test Me". Note that machine name of the content type should be "test_me". This is important because Red Test identifies content based on its machine name and not its label.
Remove the body field from the "Test Me" content type and add a new field: "Test Me Body" (machine name: field_test_me_body). It should be a "Long Textarea With Summary" field.
First we need to inform Red Test about the "Test Me" content type. Go to <DRUPAL_ROOT>/tests/folder/RedTest/entities/Node folder.
cd <DRUPAL_ROOT>/tests/RedTest/entities/Node
Create a new PHP file named TestMe.php. Create a class called TestMe which extends Node class.
<?php
namespace RedTest\entities\Node;
use RedTest\core\entities\Node;
/**
* Class TestMe
*
* @package RedTest\entities\Node
*/
class TestMe extends Node {
}
Create a new PHP file named TestMeForm.php. Create a class called TestMeForm which extends NodeForm.
<?php
namespace RedTest\forms\entities\Node;
use RedTest\core\forms\entities\Node\NodeForm;
/**
* Class TestMeForm
*
* @package RedTest\forms\entities\Node
*/
class TestMeForm extends NodeForm {
}
We are done defining the configuration. Let's start writing the test.
cd <DRUPAL_ROOT>/tests/RedTest/tests/entities/node
mkdir -p test_me/crud
cd test_me/crud
Below is the code which tests the above scenarios. The code is well-commented so it should be easy to understand what's going on.
<?php
namespace RedTest\tests\entities\node\test_me\crud;
use RedTest\core\entities\User;
use RedTest\core\RedTest_Framework_TestCase;
use RedTest\entities\Node\TestMe;
use RedTest\core\Menu;
use RedTest\core\Path;
/**
* Class AnonymousUserTest
*
* @package RedTest\tests\entities\node\test_me\crud
*/
class AnonymousUserTest extends RedTest_Framework_TestCase {
/**
* @var TestMe
*/
private static $publishedTestMeContent;
/**
* @var TestMe
*/
private static $unpublishedTestMeContent;
/**
* Create a published and an unpublished content of the type
* "Test Me".
*/
public static function setupBeforeClass() {
$options = array(
'required_fields_only' => FALSE,
'status' => 'published',
);
// Log out the user just to make sure that there is no
// logged in user at this point.
User::logout();
// Log in as user 1.
$userObject = User::loginProgrammatically(1)
->verify(get_class());
// Create a published TestMe content with all its fields
// filled with random values.
self::$publishedTestMeContent =
TestMe::createRandom(1, $options)->verify(get_class());
// Create an unpublished TestMe content with all its
// fields filled with random values.
$options['status'] = 'unpublished';
self::$unpublishedTestMeContent =
TestMe::createRandom(1, $options)->verify(get_class());
// Log the user out. After this step, the user will be
// anonymous.
$userObject->logout();
}
/**
* Make sure that anonymous user has access to view the
* published "Test Me" content.
*/
public function testPublishedViewAccess() {
// Use node_access() function to check whether user has
// access to view the published content.
$access = self::$publishedTestMeContent->hasViewAccess();
$this->assertTrue($access,
'Anonymous user does not have permission to view a
published "Test Me" content.');
// Use Menu class' hasAccess() function to check whether
// user has access to node/<nid> page. This is a more
// general function and can be used for custom paths as
// well.
$id = self::$publishedTestMeContent->getId();
$path = new Path('node/' . $id);
$access = $path->hasAccess();
$this->assertTrue($access,
'Anonymous user does not have permission to view a
published "Test Me" content.');
}
/**
* Make sure that anonymous user is able to view the
* published "Test Me" content in "full" and "teaser" view
* modes.
*/
public function testPublishedView() {
// Get the renderable array of the node in "full" view
// mode. Note that a node in "full" view mode does not
// have title inside it. The title is being rendered by
// page tpl.
$view = self::$publishedTestMeContent->view('full');
$this->assertArrayHasKey('field_test_me_body', $view,
'Anonymous user is not able to view the body field of
the published content in "full" view mode.');
}
/**
* Make sure that anonymous user does not have access to
* view the published "Test Me" content.
*/
public function testUnpublishedViewAccess() {
// Use node_access() function to check whether user has
// access to view the unpublished content.
$access =
self::$unpublishedTestMeContent->hasViewAccess();
$this->assertFalse($access,
'Anonymous user has permission to view an unpublished
"Test Me" content.');
// Use Menu class' hasAccess() function to check whether
// user has access to node/<nid> page. This is a more
// general function and can be used for custom paths as
// well.
$id = self::$unpublishedTestMeContent->getId();
$path = new Path('node/' . $id);
$access = $path->hasAccess();
$this->assertFalse($access,
'Anonymous user has permission to view an unpublished
"Test Me" content.');
}
}
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://schema.phpunit.de/4.6/phpunit.xsd"
backupGlobals="false"
backupStaticAttributes="false"
cacheTokens="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
forceCoversAnnotation="false"
mapTestClassNameToCoveredClassName="false"
processIsolation="false"
stopOnError="true"
stopOnFailure="true"
stopOnIncomplete="false"
stopOnSkipped="false"
verbose="true">
<testsuites>
<testsuite name="ParaTest Fixtures">
<directory>./RedTest/tests/entities/node/test_me</directory>
</testsuite>
</testsuites>
</phpunit>
cd <DRUPAL_ROOT>
tests/bin/paratest --phpunit=tests/bin/phpunit --processes=4 --log-junit="tests/output.xml" --configuration=tests/phpunit.xml
You should see the following output:
Running phpunit in 4 processes with tests/bin/phpunit
Configuration read from /Users/neeravm/Sites/drupal7/tests/phpunit.xml
...
Time: 780 ms, Memory: 30.50Mb
OK (3 tests, 5 assertions)
You will notice that the test completed in less than a second, more specifically in 780 ms. The same test would have taken a few seconds to run using Simpletest or Behat. Although a few seconds don't seem like much, it quickly adds up. Also Red Test is designed to run multiple scenarios in parallel and it doesn't bootstrap Drupal for each test separately. Currently we have just one test. So the speed-up by using Red Test will be even more when we add more tests.
If you did go through the example on your system and got stuck somewhere, please write it in the comment with your email id or email me at [email protected]. I can help you with the setup. If the tests passed, then write a comment and note down how much time it took to run the test!

Neerav Mehta
Neerav Mehta is the Founder & CEO of Red Crackle. With sterling qualities, Neerav’s technological acumen is firing a generation of progressive companies on the digital path. With an undergraduate degree in Electrical Engineering from India's most prestigious institution IIT Bombay and having spent seven years developing and contributing to the launch of AMD's innovative line of computer products, Neerav founded Red Crackle where he is lauded for his dynamic and innovative genius.
Let’s get you started!