测试驱动开发 - 单元测试(在CakePHP中)

4

我在学习CakePHP的单元测试时遇到了一些问题,特别是在测试数据库插入/更新时。假设我有一个模型,像这样:

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);
  }
}

我遇到的问题是在我的测试用例中:
  • 我必须提供通常从表单中检索的虚拟数据
  • 虚拟数据的格式没有考虑实际表单数据可能不正确的情况
  • 我只测试更新是否成功:为了测试这个,创建所有虚拟数据似乎需要很多工作量
这个例子可能看起来有点牵强(例如,我可以在控制器中进行update而不必为此创建额外的模型方法),但主要问题是,在测试更新/插入时,数据是虚拟数据,而从表单中检索的数据可能会有所不同,好处似乎并不超过成本。
欢呼声
感谢您的TDD和单元测试方法,希望了解您通常尝试覆盖哪些案例。

我建议你阅读一本关于这个主题的书籍,比如这本:https://leanpub.com/cakephpunittesting/ - rrd
3个回答

8

有人曾经说过,单元测试应该讲述一个故事。这种方法可以帮助您编写与您正在编码的应用程序相关的有意义的测试。为每个测试方法编写描述性名称,如:

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);
}

在讲述了不安全密码的“故事”之后,您可以编写模型代码,使新测试通过。另一个例子:

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);
}

请注意,我们正在进行更多的工作来验证更新是否正确。当测试框架开始捕捉错误和回归时,您会很高兴您做出了额外的努力。

好的描述性测试名称的一个附带优势是现在我们可以使用cake test --testdox选项以可理解的英语输出结果:

[x] Updating insecure password should fail
[x] Updating strong password should succeed

3

TDD的好处(一旦你完全理解了它):

  1. 我可以在没有浏览器的情况下调试我的代码。
  2. 如果我的代码依赖于其中的各个部分,而我(或其他人)进行更改时意外破坏了我之前成功测试过的某些东西,我的自动化单元测试将立即捕捉到这种情况。
  3. (个人)它改变了我的输入思维方式 - 不是手动将数据输入到文本字段中,我开始考虑来自脚本而不是浏览器的输入 - 真的让我更加关注对输入的清洗。
  4. 自动化测试 - 一旦系统完成,我可以运行所有测试,并在几秒钟内执行它们以确保一切正常工作,而不是尝试手动运行整个系统,这可能需要数小时,具体取决于其复杂性。

2

ddawber,

你提到了三个问题:

1.

我必须提供虚拟数据,这些数据通常会从表单中检索出来。

你应该查看一下CakePHP的fixtures

2.

虚拟数据的格式并没有考虑实际表单数据可能不正确的情况。

表单数据会根据模型的验证规则进行验证,请参见此处

3.

我只是测试更新是否成功:创建所有虚拟数据来测试这一点似乎需要很多努力。

这可以通过编写一个测试方法来简单解决(并且您只选择相关案例),同时考虑1和2。 也许你会对这样一个事实感兴趣,即CakePHP开发人员在2.0版本中从simpletest切换到phpunit,这可以帮助你计划你的努力。

无论如何,祝你在CakePHP的测试设施中好运。

编辑0: 关于代码覆盖率的第四点似乎有争议。如果你想达到100%的覆盖率,你必须编写大量的模拟对象,只是为了确保在调用控制器的操作时实际上调用了它。编写这样的代码任务应该交给框架的开发人员,而省略编写这种多余的代码则会直接影响代码覆盖率。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接