Create simpletests for the D6 version of CCK to test the new CRUD (create,
read, update, delete) API. This task is to create an overall structure for unit
tests that will ensure this functionality works, and implement a few tests
to use as a starting point for further test development.

The Simpletest module provides a framework for running automated unit
tests in Drupal. Unit testing involves taking a small portion of code, a
unit, and subjecting it to programmatic tests to prove its correctness.
This can be extremely useful to help insure that new code does not
introduce bugs into existing functionality. Thus, having a full suite of
unit tests for Drupal 6.x CCK functionality using the Simpletest module
would be a major step forward for the project and would help insure that
only high-quality code is committed.

For this task, you need to first install and familiarize yourself with the
simpletest module (use the cvs HEAD version with Drupal HEAD/6.x RC):
http://drupal.org/project/simpletest
http://drupal.org/simpletest
http://www.lullabot.com/articles/introduction-unit-testing

A very very crude start for the tests can be created from the browser with
http://drupal.org/project/simpletest_automator -- generated tests need
serious cleanup and editing.

The tests should create a user who makes various changes to the field
settings, then test that they produce the right results.

What to test in each step below:

* When checking the database structure, check two things:

** Check drupal_get_schema is the expected database schema according
to the rules above. Checking for tables and columns is probably enough,
without going as far as actual column definitions.

** Check the actual db structure matches drupal_get_schema. We can
use Schema.module's db inspection features : see
schema_compare_table() function.

* When checking a node's values, test that a node_load returns the
expected field data.

Create simpletest code for CCK that will easily build tests, i.e. using setUp and
tearDown functions to provide self-clearing test context , finding a
way to have "now re-run tests 1-10 using a different node types/fields
context".

Create two initial tests:

============================================
Test 1
Check single->multiple + sharing multiple field1
============================================

* Create three new content types : type1, type2, type3.

* Create three new nodes, one each in each content type,
node1 (type1), node2 (type2), node3 (type3)

* On content type type1, create a field, field1, a single value text field that
uses filtered text (this will create a 2 column field).
A table called 'content_type_type1 should be created with the following
columns: nid, vid, field_field1_value, field_field1_format.

* Fill in a value for node1, set the format to Full HTML.
Check that the node has the right values.

* change field1 to unlimited
The field_field1_value and field_field1_format columns should drop out of the
table 'content_type_type1' and a new table should be created called
'content_field_field1' which should have columns nid, vid, delta,
field_field1_value, and field_field1_format, with the values that
were in the previous table.

* fill in values for node1
Check that the node has the previous values in the first available slot
and that both the value and the format are correct.

* add existing field1 to type2
A new content_type_type2 table should be created with
columns nid and vid.

* fill in values for node2, and set the format to Full HTML.
Check that the new node has the right values.

* add existing field1 to type3
A new content_type_type3 table should be created with
columns nid and vid.

* fill in values for node3
Check that the new node has the right values.

* remove field1 from type3
The content_type_type3 table should disappear.
Node3 should now have no field1.

* remove field1 from type2
The content_field_field1 table should disappear.
Node 2 should have no field.

* remove field1 from type1
The content_type_type1 table should disappear.
All nodes should lose their field values.

============================================
Test 2
Check multiple->single + sharing single field1
============================================

* Create three new content types : type1, type2, type3.

* Create three new nodes, one each in each content type,
node1 (type1), node2 (type2), node3 (type3)

* Create a field, field1, a multiple value text field that uses
filtered text (to create a 2 column field) and add field1 to type1.

A table called 'content_type_type1 should be created with the following
columns: nid, vid.

A new table should be created, 'content_field_field1' with
columns nid, vid, delta, field_field1_value, and field_field1_format.

* fill in several values for node1, set the formats to Full HTML
Check that the node has the right values.

* change field1 to single
The content_field_field1 table should disappear. The
field_field1_value and field_field1_format columns should
be added to content_type_type1.

* fill in values for node1
Check that node1 retains the first value in the field.

* add existing field1 to type2
A new content_type_type2 table should be created with
columns nid and vid.

The content_type_type1 table should lose the field_field1_value
and field_field1_format columns, and a new content_field_field1
table should be created with columns nid, vid, field_field1_value,
and field_field1_format.

* fill in a value for node2
Check that node1 did not lose its value and that node 2 has the right
value.

* add field1 to type3
A new content_type_type3 table should be created with
columns nid and vid.

* fill in a value for node3
Check that all nodes have the right values.

* remove field1 from type3
The table content_type_type3 should disappear.
Node 3 should lose the field value.

* remove field1 from type2
The table content_type_type2 should disappear.
The table content_field_field1 should disappear.
The table content_type_type1 should now have
columns nid, vid, value, format

Node 2 should lose the field value.
Node 1 should still have the right value.

* remove field1 from type1
The table content_type_type1 should disappear.
None of the nodes should have a field value.

This suite should be written as a single .test file and should achieve
RTBC status at http://drupal.org/node/211215

Resources
CCK :
- http://drupal.org/node/101723 (CCK handbook), especially http://drupal.org/node/82661, http://drupal.org/node/133705
- Robert Douglas's intro to CCK at http://www.lullabot.com/articles/an_introduction_to_the_content_construc...
- PHPDocs for content_field_instance_* CRUD functions in CCK's content_crud.inc

Simpletests :
- http://drupal.org/simpletest (Simpletest handbook)
- Angie Byron's and Robert Douglas's unit test explanation at http://www.lullabot.com/articles/drupal-module-developer-guide-simpletes...

Required modules
http://drupal.org/node/96064 (CCK HEAD (for D6))
http://drupal.org/project/simpletest (Simpletest module)
http://drupal.org/project/schema (Schema module)

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

aclight’s picture

Title: GHOP Task » GHOP #157: Create simpletests for CCK field storage

The official task associated with this issue can be found at: http://code.google.com/p/google-highly-open-participation-drupal/issues/...

corsix’s picture

How mature is drupal test case's drupalCreateContentType function? I'm using it three times in a test function, and getting alot of simpletest exceptions when later, node_delete($nid); and node_type_delete($type); are called in the tear down.

So as a minimal test:

   function testExample() {
    $type1 = $this->drupalCreateContentType();
    $node1 = $this->drupalCreateNode(array('type' => $type1->name));
  } 

Causes 1 pass and 22 expections:

status: <em>simpletest_oEuDeMlu</em> has been deleted. at [E:\HTML\Apache\users\drupal60_head\modules\simpletest\drupal_test_case.php line 488]	OK
Unexpected PHP error [Undefined index: created] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\simpletest\drupal_test_case.php line 56]	EXCEPTION
Unexpected PHP error [Invalid argument supplied for foreach()] severity [E_WARNING] in [E:\HTML\Apache\users\drupal60_head\modules\cck\content.module line 1037]	EXCEPTION
Unexpected PHP error [Invalid argument supplied for foreach()] severity [E_WARNING] in [E:\HTML\Apache\users\drupal60_head\modules\cck\content.module line 1077]	EXCEPTION
Unexpected PHP error [Invalid argument supplied for foreach()] severity [E_WARNING] in [E:\HTML\Apache\users\drupal60_head\modules\cck\content.module line 1037]	EXCEPTION
Unexpected PHP error [Invalid argument supplied for foreach()] severity [E_WARNING] in [E:\HTML\Apache\users\drupal60_head\modules\cck\content.module line 953]	EXCEPTION
Unexpected PHP error [Invalid argument supplied for foreach()] severity [E_WARNING] in [E:\HTML\Apache\users\drupal60_head\modules\cck\content.module line 990]	EXCEPTION
Unexpected PHP error [Invalid argument supplied for foreach()] severity [E_WARNING] in [E:\HTML\Apache\users\drupal60_head\modules\cck\content.module line 920]	EXCEPTION
Unexpected PHP error [Invalid argument supplied for foreach()] severity [E_WARNING] in [E:\HTML\Apache\users\drupal60_head\modules\cck\content.module line 1037]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\cck\content_crud.inc line 588]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\cck\content_crud.inc line 592]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\cck\fieldgroup.module line 495]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\cck\fieldgroup.module line 496]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\taxonomy\taxonomy.module line 726]	EXCEPTION
yched’s picture

I'd rather use

$node1 = $this->drupalCreateNode(array('type' => $type1->type));

than

$node1 = $this->drupalCreateNode(array('type' => $type1->name));

but I don't think this is the cause.

- the first warning looks like a bug in drupalCreateNode() : refers to $default['created'], but the 'created' key isn't initialized (only 'changed'...)
- for the other warnings : could you make sure you use latest CCK HEAD ? The line numbers do not seem to match the errors mentioned.

corsix’s picture

These should match up: (changing name to type has no effect on these)

status: <em>simpletest_AqQJbKvT</em> has been deleted. at [E:\HTML\Apache\users\drupal60_head\modules\simpletest\drupal_test_case.php line 488]	OK
Unexpected PHP error [Undefined index: created] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\simpletest\drupal_test_case.php line 56]	EXCEPTION
Unexpected PHP error [Invalid argument supplied for foreach()] severity [E_WARNING] in [E:\HTML\Apache\users\drupal60_head\modules\cck\content.module line 1027]	EXCEPTION
Unexpected PHP error [Invalid argument supplied for foreach()] severity [E_WARNING] in [E:\HTML\Apache\users\drupal60_head\modules\cck\content.module line 1067]	EXCEPTION
Unexpected PHP error [Invalid argument supplied for foreach()] severity [E_WARNING] in [E:\HTML\Apache\users\drupal60_head\modules\cck\content.module line 1027]	EXCEPTION
Unexpected PHP error [Invalid argument supplied for foreach()] severity [E_WARNING] in [E:\HTML\Apache\users\drupal60_head\modules\cck\content.module line 943]	EXCEPTION
Unexpected PHP error [Invalid argument supplied for foreach()] severity [E_WARNING] in [E:\HTML\Apache\users\drupal60_head\modules\cck\content.module line 980]	EXCEPTION
Unexpected PHP error [Invalid argument supplied for foreach()] severity [E_WARNING] in [E:\HTML\Apache\users\drupal60_head\modules\cck\content.module line 910]	EXCEPTION
Unexpected PHP error [Invalid argument supplied for foreach()] severity [E_WARNING] in [E:\HTML\Apache\users\drupal60_head\modules\cck\content.module line 1027]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\cck\content_crud.inc line 588]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\cck\content_crud.inc line 592]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\cck\fieldgroup.module line 495]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\cck\fieldgroup.module line 496]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\taxonomy\taxonomy.module line 726]	EXCEPTION

If not, the lines in question from content.module / crud.inc are;

 foreach ($type['fields'] as $field) { // 1027
foreach ($type['fields'] as $field) { // 1067
foreach ($type['tables'] as $table) { // 943
foreach ($type['fields'] as $field) { // 980
foreach ($type['tables'] as $table) { // 910

$fields = content_field_instance_read(array('type_name' => $info->type)); // 588
$table = _content_tablename($info->type, CONTENT_DB_STORAGE_PER_CONTENT_TYPE); // 592 
yched’s picture

OK, thanks for the update.

Several things happen here :
- drupalCreateContentType() needs to clear core's cached type info after saving the new content type.
I'll roll a patch for drupal_test_case.php, for now you can manually change the code in drupalCreateContentType() to :

function drupalCreateContentType($settings = array()) {
  (...)
  
  node_type_save($type);
  node_types_rebuild(); // <--

  $this->_cleanupContentTypes[] = $type->type;
  return $type;
}

- CCK's own cached info about content types needs to be cleared as well.
Currently, content.module reacts to node_type_save by *flagging* a rebuild, that gets executed on next page request (this was to done to save multiple rebuilds in one request). This is obviously not enough for us here. Not sure yet how we want to fix this, for now you need to call content_clear_type_cache() after creating your content types :

function testExample() {
  $type1 = $this->drupalCreateContentType();
  content_clear_type_cache();
  $node1 = $this->drupalCreateNode(array('type' => $type1->type));
}

Works for me, no errors.

[edit : $type1->type, not $type1->name - wrong copy/paste]

corsix’s picture

Another bug in drupalCreateContentType:
$name = $this->randomName(3, 'type_');
Should be:
$name = strtolower($this->randomName(3, 'type_'));
As the machine-readable name for content types should contain only lowercase, numbers and underscores (atleast according to the content type creation form in admin), and/or node_type_save should refuse names with uppercase.

corsix’s picture

Status: Active » Needs review
FileSize
10 KB

Written first draft of the test 1.

corsix’s picture

I'm getting a strange behaviour of drupalCreateContentType when used within two tests;

  function testA() {
    $type = $this->drupalCreateContentType();
  }
  
  function testB() {
    $type = $this->drupalCreateContentType();
  }

Generates 14 exceptions:

Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\cck\content_crud.inc line 588]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\cck\content_crud.inc line 592]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\cck\fieldgroup.module line 495]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\cck\fieldgroup.module line 496]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\comment\comment.module line 264]	EXCEPTION
Unexpected PHP error [Trying to get property of non-object] severity [E_NOTICE] in [E:\HTML\Apache\users\drupal60_head\modules\taxonomy\taxonomy.module line 726]	EXCEPTION

Commenting out the creation line from either test causes the exceptions to disappear.

corsix’s picture

FileSize
14.24 KB

Implemented 2nd test and made a number of refactorings.

yched’s picture

Woo, impressive job !
Still wrapping my head on the node data part, here's my comments so far :

- The content_simpletest() hook is not needed anymore with latest simpletest.module. Thus, you can simply upload your content_crud.test file in the thread without rolling a patch

- The set of helper functions would probably deserve a ContentCrudTest superclass on their own, with the actual tests deriving from it.

- Some functions are only internal helpers, not intended to be actually used in tests, right ? If so, they might be worth prefixing with a '_', just to make the 'test API' clearer.

- createFieldText() : I'd rather have text_processing explicitly set than made a default.
Also, that function should probably make sure text.module is enabled, but I'm really nitpicking :-).

- createRandomTextFieldData(), getContentTypeTableName(), getFieldTableName() function definitions should be moved up next to the group of schema related assert functions.

- assert messages should be unified : 'Table x should not exist' does not match 'Node data y is correct' and 'Table z matches schema' pattern

- In the tests themselves, we should probably avoid the random type and field name generation - too complicated to track. Sticking to fields and types with definite names ('st_fN', 'st_tN') would be easier.

- Not sure assertSchemaMatchesField() should automatically add 'delta'. Let it be explicitely expected in the $extra_columns (simply don't auto-prefix that one)

- Do you think the assertTableNotExists() used in the actual tests could be handled by assertSchemaMatchesContentType / assertSchemaMatchesField ?
More generally, I've been thinking about simplifying schema checking functions and use a single
assertSchemaMatchesTables() function, with an exhaustive array as parameter :

$tables = array(
  'per_field' => array(
    'st_f1' => array('delta', 'field_f1' => array('value, 'format'),
    'st_f2' => NULL,    // no content_field_f2 table
  ),
  'per_type' => array(
    'st_t1' => array('field_f2' => array('value'), 'field_f3' => array('value', 'format')), 
    'st_t2' => array(), // only 'nid' and 'vid' columns
    'st_t3' => NULL,    // no content_type_t3 table
  ),
);
$this->assertSchemaMatchesTables($tables);

Requires a little more writing in the tests themselves, but makes it crystal clear what we expect on each step, while not needing to figure out what assert function should be called. What do you think ?

- Getting fails for 'Table content_type_type_* should not exist' : ok, that's bug http://drupal.org/node/201329 (tables not cleaned up on field deletion)

- Getting a fail for 'Node data [field_*][0][value] is correct' on line 352. This means a bug in CCK or in the test :-) Do you get that as well ?

- It seems I'm not getting any of the exceptions you mention in #8 ?

yched’s picture

OK, I spent some more time on the node checks part.
Not completely simple. The dangerr here is to over-engineer this and force us to be sure our test framework is bug-free itself :-)
This being said, the main goal of this task is to provide the right tools for writing tests, so finding the right balance is not easy.

A few general remarks :
- More code comments would be really welcome at places. A function like _compareArrayForChanges for instance is a little obscure.
- This includes PHPDoc for the functions : what are the arguments, what's their type (a node, a node id, a type, a type name...)
- More generally, variables and parameters names are a bit confusing : sometimes $node is a node, sometimes it's an index... It's important that variable names reflect what they contain (type object, type index in $this, node, field, field name, etc...), more than what we use them for ($share_with...), which should be told by code comments. This is true for a large part of the current code, and this would make the test API easier to grasp and the tests themselves easier to read and check.

More specific to the node tests code :
- acquireNodes() : I'd think $count should be the number of nodes created for each content type (not the *total* number of nodes)
- assertNodeStillUnchanged() : could have a simpler name ?
- Not sure we want the shorthands allowed by parts like :

function assertNodeStillUnchanged($nid = NULL, $changes = NULL) {
  if (!isset($nid)) {
    $nid = $this->previous_node_changes_nid;
  }
  if (!isset($changes)) {
    $changes = $this->previous_node_changes;
  }

Shorthands make tests easier to write, but more complicated to follow.

- Similarly to my remark on schema comparison in my previous post : I think it would be clearer if we explicitely wrote what the node should be and tested it using one single test function, that takes care of checking everything that should is here and nothing's here that shouldn't (only looking at $node->field_* keys, of course - we could probably use a helper function that returns the field_* namespace part of a node).

$values = array(
  'field_st_f1' => array(array('value' => 'foo', 'format' => 0), array('value' => 'bar', 'format' => 0)),
  'field_st_f2' => NULL // no field_st_f2 should be found.
);
$this->saveNodeValues($node, $values); // Merges the new values in the node and saves it.
$this->assertNodeValues($node->nid, $values); // Loads the node and compares.

Your experience on writing the tests makes your advice precious here, of course :-)

I suggest we primarily focus on the db schema checks right now. At worse, if we can get this straight and clean and committed, then we have gained something really valuable, and node data chacks can be tackled later.

KarenS’s picture

@corsix, this is a great start for this project. Any feedback from you on yched's comments? I'd like to be sure you get credit for this before tomorrow. Yched is most likely not going to be available this weekend (he should be en route to the US for our data architecture conference) but I'll try to be available to work on this.

corsix’s picture

I'm currently acting upon his comments, and should have a new version in a few hours.

corsix’s picture

FileSize
4.55 KB

- The content_simpletest() hook is not needed anymore with latest simpletest.module. Thus, you can simply upload your content_crud.test file in the thread without rolling a patch
Attached as tar.gz, as .test files aren't allowed :[

- The set of helper functions would probably deserve a ContentCrudTest superclass on their own, with the actual tests deriving from it.
Done

- Some functions are only internal helpers, not intended to be actually used in tests, right ? If so, they might be worth prefixing with a '_', just to make the 'test API' clearer.
Prefixed the functions not intended to be called from outside, and pruned off some unused functions.

- createFieldText() : I'd rather have text_processing explicitly set than made a default.
Also, that function should probably make sure text.module is enabled, but I'm really nitpicking :-).

Done

- createRandomTextFieldData(), getContentTypeTableName(), getFieldTableName() function definitions should be moved up next to the group of schema related assert functions.
Moved them to correct places, and started each group of functions with a short comment saying what group it is

- assert messages should be unified : 'Table x should not exist' does not match 'Node data y is correct' and 'Table z matches schema' pattern
Changed the message for tables being absent. I didn't change any others, as I assume you were looking at the "not" in the message, which nothing else has.

- In the tests themselves, we should probably avoid the random type and field name generation - too complicated to track. Sticking to fields and types with definite names ('st_fN', 'st_tN') would be easier.
Given types the name simpletest_tN and fields the name simpletest_fN

- Not sure assertSchemaMatchesField() should automatically add 'delta'. Let it be explicitely expected in the $extra_columns (simply don't auto-prefix that one)
- Do you think the assertTableNotExists() used in the actual tests could be handled by assertSchemaMatchesContentType / assertSchemaMatchesField ? ...

Changed to using a assertSchemaMatchesTables function for all table assertions.

- Getting a fail for 'Node data [field_*][0][value] is correct' on line 352. This means a bug in CCK or in the test :-) Do you get that as well ?
I get it, but not sure of the cause at the moment.

- It seems I'm not getting any of the exceptions you mention in #8 ?
I'm not either any more, which is perplexing, but convenient.

- More code comments would be really welcome at places. A function like _compareArrayForChanges for instance is a little obscure.
- This includes PHPDoc for the functions : what are the arguments, what's their type (a node, a node id, a type, a type name...)

Given all the functions in the test case class a docblock

- More generally, variables and parameters names are a bit confusing...
Tried to standardise functions so that they can take either an entity, or the index of an acquired entity, with a argument named $node or $content_type. Changed some variable names to include what they contain, but there are probably some more that can be changed.

- acquireNodes() : I'd think $count should be the number of nodes created for each content type (not the *total* number of nodes)
Done.

- assertNodeStillUnchanged() : could have a simpler name ?
Now called assertNodeValues, with the partner function called assertNodeSaveValues

- Not sure we want the shorthands allowed by parts like :
function assertNodeStillUnchanged($nid = NULL, $changes = NULL) {

The function now requires both parameters. The *field functions still remember the last used field and use it as default, but I think for fields it is clearer as we only have one field?

- Similarly to my remark on schema comparison in my previous post : I think it would be clearer if we explicitely wrote what the node should be and tested it using one single test function...
Haven't done this yet, as the DB schema checks were deemed more important.

KarenS’s picture

Status: Needs review » Reviewed & tested by the community

Excellent job!

The documentation looks excellent and I think you've addressed all of yched's issues.

There are some failures, but I think they may be genuine failures and they need to be investigated.

I'm inclined to mark this RTBC. I think you accomplished the goal of getting a framework ready to use that we can continue to tweak.

Thanks!

yched’s picture

(Landed in Chicago, finally got a chance to check my mail)
Thanks for the update. Completely agreed on RTBC.

I'd still be interested in your opinion on the shaping on node tests assert API, so that we can possible refine, but there's no reason it should hold the current patch, which more than fulfills the task at hand here .

Thanks for the great job, Corsix ! I assume you don't need to be reminded to attach the latest code to the google tracker for the task :-)

CCK gets simpletests ! I wouldn't be surprised to learn that the Ewoks are dancing right now...

yched’s picture

Status: Reviewed & tested by the community » Fixed

Committed to HEAD. Great job.

Anonymous’s picture

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for two weeks with no activity.