php - 如何让我的 PHPUnit 测试更简洁、更短?

标签 php unit-testing mocking phpunit

我正在为我的 Web 应用程序编写的 PHPUnit 测试的长度和不透明性让我很吃力。测试中的代码似乎比他们正在测试的代码多一个数量级。

例如,假设我的网站有一个 CatController 对象,其上有这个方法:

public function addCat(Default_Model_Cat $cat)
{
    $workflow = $this->catWorkflowFactory->create(array($this->serviceExecutor));
    $workflow->addCat($cat);
}

我必须创建以彻底测试它的单元测试如下所示:

public function testAddCat()
{
    $cat = $this->getMockBuilder('Default_Model_Cat')
        ->disableOriginalConstructor()
        ->getMock();
    $controller = $this->getMockBuilder('CatController')
        ->disableOriginalConstructor()
        ->setMethods(array('none'))
        ->getMock();
    $workflow = $this->getMockBuilder('Default_Model_Workflow_Cat')
        ->setMethods(array('addCat'))
        ->disableOriginalConstructor()
        ->getMock();
    $workflow->expects($this->once())
        ->method('addCat')
        ->with($cat);
    $controller->serviceExecutor = $this->getMockBuilder('ServiceExecutor')
        ->disableOriginalConstructor()
        ->getMock();
    $controller->catWorkflowFactory = $this->getMockBuilder('Factory')
        ->disableOriginalConstructor()
        ->setMethods(array('create'))
        ->getMock();
    $controller->catWorkflowFactory->expects($this->once())
        ->method('create')
        ->with($controller->serviceExecutor)
        ->will($this->returnValue($workflow));
    $controller->addCat($cat);
}

是否有任何语法可用于使单元测试更短且更易于阅读?例如,而不是说“这个对象是一个模拟对象,将在其上调用此方法,当在其上调用此方法时,它将使用此参数调用一次并返回此值”如果我能只需说类似 once(object->method(argument)) => $returnvalue 的内容即可。

最佳答案

您可以将类设计得越多,使其无需模拟即可在单元测试中使用,您需要编写的模拟代码就越少。但是对于上面的例子,我的第一 react 是这个方法不需要单元测试,因为它并没有真正执行任何逻辑,并且在编写后不会改变。

话虽这么说,假设您将需要此类的其他方法中的工作流实例,将创建它的代码提取到新方法中。这允许您为每个测试模拟该方法,并且只在一个测试中进行更长的模拟。

例如,如果您还有一个 removeCat() 方法,它将如下所示:

public function addCat(Default_Model_Cat $cat) {
    $this->createWorkflow()->addCat($cat);
}

public function removeCat(Default_Model_Cat $cat) {
    $this->createWorkflow()->removeCat($cat);
}

public function createWorkflow() {
    return $this->catWorkflowFactory->create(array($this->serviceExecutor));
}

上面的方法非常简短,确实不需要单元测试,但现在会更短一些:

public function testAddCat() {
    $cat = $this->getMockBuilder('Default_Model_Cat')
        ->disableOriginalConstructor()
        ->getMock();
    $controller = $this->getMockBuilder('CatController')
        ->disableOriginalConstructor()
        ->setMethods(array('createWorkflow'))
        ->getMock();
    $workflow = $this->getMockBuilder('Default_Model_Workflow_Cat')
        ->setMethods(array('addCat'))
        ->disableOriginalConstructor()
        ->getMock();
    $controller->expects($this->once())
        ->method('createWorkflow')
        ->will($this->returnValue($workflow));
    $workflow->expects($this->once())
        ->method('addCat')
        ->with($cat);
    $controller->addCat($cat);
}

如果 Controller 中有很多这样的方法,您可以在测试用例中创建辅助方法来创建模拟。最后,你真的需要禁用模拟中的原始构造函数吗?我很少需要自己这样做。

关于php - 如何让我的 PHPUnit 测试更简洁、更短?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8359349/

相关文章:

php - 在 PHP 中使用 MySQLi 准备语句,得到 "No data supplied for parameters in prepared statement "

java - 在方法内部创建模拟对象正在测试以验证传递的参数

java - 带有局部变量的 Mockito

php - 我所有页面的一个内部 php 脚本

php - 显示用于复制/粘贴的任何网站源代码

php - 在 PHPUnit 中模拟具有内部依赖关系的对象

c++ - 如何确定现有类是否可以进行单元测试?

java - 从 Groovy 测试用例模拟 Java 类

php - 当我尝试在我的项目 laravel 6.x 上使用 redis 时,它显示此错误消息

java - JUnit 4.8.1/Maven 简单测试不起作用