3

我正在尝试实现一个简单的验证器类系统,它尊重 SOLID 原则并用于单元测试目的。

假设我有一些简单的验证器(强制、整数、大于...),现在我想实现一个更复杂的验证器,它调用几个简单的验证器(例如使用一些验证器的表单验证器)

这非常受 Zend 和其他框架的启发。

问题是,这里如何应用或违反 SOLID 原则,以及应该如何对这个模型进行单元测试?

我想我可以轻松地对每个简单的验证器进行单元测试,但不能对复杂的 FormValidator 进行单元测试

interface ICheckable
{
    public function check($data);
}

class MandatoryValidator implements ICheckable
{
    private $_property;
    
    public function __construct($property)
    {
        $this->_property = $property;
    }
    
    public function check($data)
    {
        return isset($data[$property]);
    }
}

class IntegerValidator implements ICheckable
{
    ...
}

class FormValidator implements ICheckable
{
    public function check($data)
    {
        $mandatoryValidator = new MandatoryValidator(array('LOGIN'));
        
        if ($mandatoryValidator->check($data) == false)
        {           
            return false;
        }
        
        $integerValidator = new IntegerValidator();
        
        if ($integerValidator->check($data['AMOUNT']) == false)
        {           
            return false;
        }
        
        ...
        return true;
    }
}
4

1 回答 1

3

首先 - ICheckable 接口做得很好。这是一个好的开始。

让我们解决 S. 单一责任原则:

这就是“一个班级应该只有一个改变的理由”的原则。 S.在所有班级中都受到尊重吗?(简单的责任。)

目前的两个验证者都尊重这一点。

FormValidator 是否只有一项职责?我可以看到它做了 3 件事:

  1. 创建验证器。
  2. 调用 2 个验证器。
  3. 检查验证器结果。

这种设计的问题是每次你有一个新的Validator,你都必须创建它,调用它,并检查它的返回值。这违反了 SOLID 原则中的 O。(开关)

表单验证器应收到 ICheckable 的“自定义”列表。这个“自定义”列表也应该实现 ICheckable,这样你就可以调用它。此“自定义”列表将遍历其 ICheckable 列表。那将是它唯一的责任。

然后,必须评估结果。当一个函数返回一个值时,你必须处理它。一般来说,这意味着更多的代码,一个额外的 IF 语句。这两个应该给你一个提示:太多的责任。

因此,为了使这个 SOLID,您应该向您的验证器传递一个回调接口,该接口将用于处理验证器输出。您的示例非常简单,验证器返回 true 或 false。可以用两种“输出”方法来表示——Validated() 或 ValidationFailed()。O_o,对于您的验证器来说,这看起来是一个非常好的“输出”接口,并且可以由 FormValidator 实现。这种设计将符合 SOLID 的原则。

请记住,当您第一次创建 FormValidator 时,您必须创建两个 Validator、自定义列表并将所有内容连接在一起。

然后,您将能够非常快速地对所有非常简单的类进行单元测试。(尝试先开始编写测试)

注意:一般来说,如果你处理得当,其他原则很容易实现。

希望这可以帮助。如果您需要更多信息,请与我们联系。

于 2013-10-07T23:27:45.093 回答