开发者

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() {
    $tmpDat开发者_StackOverflow中文版a = 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


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


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.


ddawber,

you are mentioning three points:

1.

I have to provide dummy data that would normally be retrieved from forms

You should take a look into CakePHP's fixtures

2.

The format of the dummy data does not take into account the fact that the actual form data might be incorrect

Form data is validated against the model's validation rules, see here.

3.

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 should then simply be solved by writing a test method (and you pick only relevant cases), taking 1. and 2. into account. Maybe you are interested in the fact, that the CakePHP devs switch from simpletest to phpunit in the 2.0 release, which could help you planning your efforts.

Good journey into CakePHP's testing facility anyway.

Edit0: The forth point on code coverage seems controversial. If you would go for 100% coverage, you would have to write lots of mock objects, just to make sure that a controller's action is actually called when you call it. Writing something like this is imho a task for the developers of the framework, and omitting to write superfluous code of this kind directly hits the code coverage.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜