Drupal 6: Using Drupal SimpleTest To Test Nodes With CCK Values

SimpleTest is a great way to test your modules, but it can take a bit of setting up. For every test that is run SimpleTest effectively has a fresh install of Drupal, so if you need to test a particular function you need to have everything in place before you run the test. I was recently testing a migration module that I had written and needed to create nodes with a variety of CCK fields, which is quite common in Drupal site setups. In order to test that a CCK field saves the data for a test you need to do the following in the setUp() method, remember that this all happens before any tests are run.

  1. Include the Content module along with any sub modules you might need (eg, Text, Number).
  2. Set up and save your content type.
  3. Set up and save each CCK field you need.
  4. Create and log in a user to run the test with.

CCK stores its fields as an associative array of items that detail how each field should be created and to create a field in CCK you need to pass this array to a function called content_field_instance_create(). This sounds straightforward enough, but this array is quite large and creating it correctly is definitely be a lengthy process. Luckily, there is a short-cut to writing this array out by hand, which involves the CCK function content_fields().

Create your node type in the same way as you normally would inside the admin of your Drupal install, with all of the associated CCK fields. Make a note of all of the field names you want to test. For each field you want, use the content_fields() function in the following way.

drupal_set_message('<pre>' . var_export(content_fields('FIELD NAME', 'CONTENT TYPE NAME'), true) . '</pre>');

So, for a content type I have called "testtype" I have created a text field called "field_test_field", so I would call the function in the following way.

drupal_set_message('<pre>' . var_export(content_fields('field_test_field', 'testtype'), true) . '</pre>');

This function will print out a large array in the message area containing the definition of the field you have defined, so for the above example I would get the following:

array (
  'field_name' => 'field_test_field',
  'type_name' => 'testtype',
  'display_settings' => 
  array (
    'label' => 
    array (
      'format' => 'above',
      'exclude' => 0,
    ),
    'teaser' => 
    array (
      'format' => 'default',
      'exclude' => 0,
    ),
    'full' => 
    array (
      'format' => 'default',
      'exclude' => 0,
    ),
    4 => 
    array (
      'format' => 'default',
      'exclude' => 0,
    ),
  ),
  'widget_active' => '1',
  'type' => 'text',
  'required' => '1',
  'multiple' => '0',
  'db_storage' => '1',
  'module' => 'text',
  'active' => '1',
  'locked' => '0',
  'columns' => 
  array (
    'value' => 
    array (
      'type' => 'text',
      'size' => 'big',
      'not null' => false,
      'sortable' => true,
      'views' => true,
    ),
  ),
  'text_processing' => '0',
  'max_length' => '',
  'allowed_values' => '',
  'allowed_values_php' => '',
  'widget' => 
  array (
    'rows' => 5,
    'size' => '100',
    'default_value' => 
    array (
      0 => 
      array (
        'value' => '',
        '_error_element' => 'default_value_widget][field_test_field][0][value',
      ),
    ),
    'default_value_php' => NULL,
    'label' => 'Test',
    'weight' => '31',
    'description' => '',
    'type' => 'text_textfield',
    'module' => 'text',
  ),
)

Copy and paste this array definition into your code and assign it to a variable. You can then pass this variable into the content_field_instance_create() function to get CCK to build the field inside your node type.

$field = array (
  'field_name' => 'field_test_field',
  'type_name' => 'testtype',
  'display_settings' => 
  array (
// snip....
  ),
);

content_field_instance_create($field);

The code I have detailed above is useful for creating tests in Drupal SimpleTest, but it can also be used whenever you want to programmatically setup nodes in Drupal.

Before we can test this out we need do three things, the first is add the modules we need to run the tests, the second is to create our custom content type and finally we need create a user with enough privileges to create and view the nodes. With all this in place we now have a setUp() method that looks like the following:

    public function setUp() {
        // Load modules
        parent::setUp('content', 'text');

        // create node type
        $this->drupalCreateContentType(array(
            'type' => 'testtype',
            'name' => 'testtype',
        ));

        // Snipped out the custom content type creation...

        // Create and log in our privileged user.
        $privileges = array(
            'access content',
            'create testtype content',
            'edit any testtype content'
            );
        $this->privileged_user = $this->drupalCreateUser($privileges);
        $this->drupalLogin($this->privileged_user);
    }

Now we are ready to run some tests on the CCK field. The following is a test method that creates a node and then makes sure that the data entered is the data retrieved on page. Once this is in place you can run your test from the SimpleTest admin interface.

    /**
     * Add a node and test that the content has been added.
     */
    public function testCreateTestNode() {

        // Create node content
        $node_array = array(
         'title' => 'Node title',
         'body' => 'Node body',
         'field_test_field[0][value]' => 'wibble',
        );

        // Save node
        $this->drupalPost('node/add/testtype', $node_array, t('Save'));

        // Test deault fields
        $this->assertRaw('Node title', t('Title content found.'));
        $this->assertRaw('Node body', t('Body content found.'));
        
        // Test CCK field content.
        $this->assertRaw('wibble', t('Test field content found.'));
    }

This won't always work in this way, especially if you have set your fields to not display on the node page. In which case you can load the node directly and change the assertRaw() calls to assertEquals() in order to test.

Note that you can't use the drupalCreateNode() method here to create your node as it only accepts the default node attributes and won't save any CCK data that you give it.

Here is the full test class.

<?php

class TestModule_Test extends DrupalWebTestCase {

    /**
     * @var null Used to store a user who can interact with the system.
     */
    public $privileged_user;

    /**
     * Set up.
     */
    public function setUp() {
        // Load modules
        parent::setUp('content', 'text');

        // create node type
        $this->drupalCreateContentType(array(
            'type' => 'testtype',
            'name' => 'testtype',
        ));

        $field = array(
            'field_name' => 'field_test_field',
            'type_name' => 'testtype',
            'display_settings' =>
            array(
                'label' =>
                array(
                    'format' => 'above',
                    'exclude' => 0,
                ),
                'teaser' =>
                array(
                    'format' => 'default',
                    'exclude' => 0,
                ),
                'full' =>
                array(
                    'format' => 'default',
                    'exclude' => 0,
                ),
                4 =>
                array(
                    'format' => 'default',
                    'exclude' => 0,
                ),
            ),
            'widget_active' => '1',
            'type' => 'text',
            'required' => '1',
            'multiple' => '0',
            'db_storage' => '1',
            'module' => 'text',
            'active' => '1',
            'locked' => '0',
            'columns' =>
            array(
                'value' =>
                array(
                    'type' => 'text',
                    'size' => 'big',
                    'not null' => false,
                    'sortable' => true,
                    'views' => true,
                ),
            ),
            'text_processing' => '0',
            'max_length' => '',
            'allowed_values' => '',
            'allowed_values_php' => '',
            'widget' =>
            array(
                'rows' => 5,
                'size' => '100',
                'default_value' =>
                array(
                    0 =>
                    array(
                        'value' => '',
                        '_error_element' => 'default_value_widget][field_test_field][0][value',
                    ),
                ),
                'default_value_php' => NULL,
                'label' => 'Test',
                'weight' => '31',
                'description' => '',
                'type' => 'text_textfield',
                'module' => 'text',
            ),
        );

        content_field_instance_create($field);

        // Create and log in our privileged user.
        $privileges = array(
            'access content',
            'create testtype content',
            'edit any testtype content'
        );
        $this->privileged_user = $this->drupalCreateUser($privileges);
        $this->drupalLogin($this->privileged_user);
    }

    /**
     * Create an array of options for the simpletest module.
     *
     * @return array The array of options
     */
    public function getInfo() {
        return array(
            'name' => t('Test Module Insert Node Test'),
            'description' => t('Test to insert a node with CCK fields.'),
            'group' => t('Test Module'),
        );
    }

    /**
     * Add a node and test that the content has been added.
     */
    public function testCreateTestNode() {

        // Create node content
        $node_array = array(
            'title' => 'Node title',
            'body' => 'Node body',
            'field_test_field[0][value]' => 'wibble',
        );

        // Save node
        $this->drupalPost('node/add/testtype', $node_array, t('Save'));

        // Test deault fields
        $this->assertRaw('Node title', t('Title content found.'));
        $this->assertRaw('Node body', t('Body content found.'));

        // Test CCK field content.
        $this->assertRaw('wibble', t('Test field content found.'));
    }

}

 

Comments

Thanks a million. I was banging my head on the wall trying to figure this out. This post helped me a lot.
Permalink

Add new comment

The content of this field is kept private and will not be shown publicly.
CAPTCHA
4 + 0 =
Solve this simple math problem and enter the result. E.g. for 1+3, enter 4.
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.