首页 > 解决方案 > PHP 单元测试——这是否被过度嘲笑了?-- 公共方法循环/调用其他公共方法

问题描述

功能性

我有一个 Laravel 项目,我在其中扩展Illuminate\Database\Eloquent\Builder为一个AbstractSearch类,以引入一个params()方法,该方法在扩展时调用applyParams()要定义的抽象方法AbstractSearch

例子:

$models = (new ModelSearch)
    ->params(['name' => 'Model', 'createdBefore' => now()])
    ->with(['modelCategory', 'modelType'])
    ->paginate();

applyParams()负责从底层查询中获取数组参数params()并正确构建底层Illuminate\Database\Query\Builder查询。

该类AbstractSearch允许通过受保护的$casts属性和castParams(array $params = [])方法转换这些参数。

castParams()遍历受保护的$casts属性并调用$this->castParam($params, $field, $cast)每个元素。

现在,两者castParams()castParam()都是公共方法,即使以castParam()这种方式调用的可能性几乎为零。

相关节选AbstractSearch

public function params(array $params = [])
{
    return $this->applyParams(
        $this->prepareParams($params)
    );
}

abstract function applyParams(array $params = []);

public function prepareParams(array $params = []) : array
{
    return $this->castParams(
        $this->applyDefaults($params)
    );
}

public function applyDefaults(array $params = []) : array
{
    foreach ($this->defaults as $field => $value) {
        data_fill($params, $field, $value);
    }

    return $params;
}

public function getCasts()
{
    return $this->casts;
}

public function castParams(array $params = []) : array
{
    foreach ($this->getCasts() as $field => $cast) {
        $this->castParam($params, $field, $cast);
    }

    return $params;
}

public function castParam(&$params, $field, $cast)
{
    if (! isset($params[$field])) {
        return;
    }

    switch ($cast) {
        case 'date':
        case 'datetime':
            if (! $params[$field] instanceof Carbon) {
                $params[$field] = Carbon::parse($params[$field]);
            }
            break;

        default:
            break;
    }
}

测试

我对这两种方法都有单元测试。大部分测试都是castParam()为了确保正确完成铸造。

的单元测试是通过对期望各种调用castParams()的类的部分模拟来完成的。AbstractSearchcastParam()

问题

我最近重新阅读了一些单元测试原则,这些原则让我质疑这门课的设置。您可以从上面的摘录中看到,有很多公共方法可能应该受到保护。事实上,唯一需要公开的方法是params().

从逻辑上讲,这params()应该是唯一的公共方法;但是,params()依赖于抽象方法applyParams(),因此任何测试params()都必须在扩展类上完成,因为结果取决于所做的事情applyParams()

所以...

  1. 我用上面两段话把自己说对了吗?这听起来对我来说是正确的,但它将涉及params()返回一个实例的测试,以及对 Builder 的底层及其查询Illuminate\Database\Eloquent\Builder进行预期更改的测试。Illuminate\Database\Query\Builder我不完全确定这是否可能。

  2. 回到castParams()部分模拟的期望,它会调用castParam()几次。如果两者都castParams()保留castParam()公共方法,并且测试应该关注可观察的行为,那么如果我同时测试两者,我不会有多余的测试吗?还是因为将经过彻底测试,所以castParam()在我的测试中模拟调用通常是可以接受的?(编辑:这个问题通常也适用于调用其他公共方法的任何公共方法。)castParams()castParam()

标签: phplaraveltestingphpunitlaravel-query-builder

解决方案


推荐阅读