Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test Driven Development - Unit Testing (in CakePHP)

I am having some issues getting my head round Unit Testing in CakePHP, in particular when testing database insert/updates. Let's say I have a model that something like this:

class User {
  var $name = 'User';

  function updatePassword($data) {
    return $this->updateAll($data);
  }
}

class UserTestCase {
  function testUpdatePassword() {
    $tmpData = array(
      'User' => array(
         'password' => sha1(uniqid('', true)) //dummy pass
    );

    $result = $this->User->updatePassword($tmpData);

    $this->assertTrue($result);
  }
}

The problem I have is that in my test case:

  • I have to provide dummy data that would normally be retrieved from forms
  • The format of the dummy data does not take into account the fact that the actual form data might be incorrect
  • I am only testing whether or not the update succeeds: it seems like a lot of effort to create all the dummy data to test this

This example might seem a bit contrived (I could do an update in the controller without having created an extra model method for example) but the main point is that, when testing update/inserts, the data is dummy data and data retrieved from forms might differ and the benefits don't seem to outweigh the costs.

Your approaches to TDD and unit testing are appreciated and an idea of what kind of coverage you generally try to give to cases would be nice.

Cheers

like image 419
dianovich Avatar asked Dec 13 '22 14:12

dianovich


2 Answers

Someone once said that unit tests should tell a story. This approach can help you to write tests that make sense in terms of the application you're coding. Write descriptive names for each test method like:

function testUpdatingInsecurePasswordShouldFail() {
    $data = array('User' => array(
        'password' => 'password'
    ));
    $result = $this->User->updatePassword($data);
    $this->assertFalse($result);

    $data = array('User' => array(
        'password' => ''
    ));
    $result = $this->User->updatePassword($data);
    $this->assertFalse($result);
}

Having told the "story" of the insecure passwords, you can then write the model code so the new test passes. Another example:

function testUpdatingStrongPasswordShouldSucceed() {
    $data = array('User' => array(
        // forget about hashing for the moment
        'password' => 'battery hoarse collect maple'
    ));
    $this->User->updatePassword($data);
    $result = $this->User->find('count', array(
        'conditions' => array(
            // making some assumptions about the test data here
            'User.username' => 'test_user1',
            'User.password' => 'battery hoarse collect maple',
        ),
    );
    $this->assertEqual($result, 1);
}

Notice we're doing a bit more work to verify the update worked correctly. When the testing framework starts picking up bugs and regressions you will be glad you made the extra effort.

One side advantage of good descriptive test names is that now we can use the cake test --testdox option to output the results in understandable English:

[x] Updating insecure password should fail
[x] Updating strong password should succeed
like image 172
contrebis Avatar answered Jan 05 '23 04:01

contrebis


Benefits of TDD for me (once you fully get your head wrapped around it):

  1. I can debug my code without a browser
  2. If my code is dependent on various parts of my code and I (or someone else) make a change that accidentally breaks something that I had tested earlier successfully, my automated unit tests will immediately catch that
  3. (Personal) It changes my thinking about input - rather than inputting data manually into a text field, I find myself starting to think about input that might be coming from a script rather than a browser - really makes me focus on sanitizing input more
  4. Automated testing - once the system is complete, I can run all of my tests and have them execute in a matter of seconds to ensure everything is working, rather than trying to run through an entire system manually, which could take a number of hours, depending on the complexity.
like image 43
Demian Brecht Avatar answered Jan 05 '23 03:01

Demian Brecht