Question

I am trying to implement a simple validator class system which respect SOLID principles and for unit testing purpose.

Suppose I have some simple validators (mandatory, integer, greaterThan ...) and now I want to implement a more complex validator which call several simple validators (example Form Validator which use some validators)

This is very inspired from Zend and other framework.

The question is, how SOLID principle are applied or violated here and how unit testing should be done for this model?

I think I could Unit Test each simple validator easily but not the complex 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;
    }
}
Était-ce utile?

La solution

First - good job with the ICheckable Interface. That's a good start.

Lets tackle the S. Single Responsibility Principle:

That's the principle that states, "a class should only have one reason to change" Is the S. Respected in all the classes? (Simple Responsibility.)

The two current validators respect this.

Is FormValidator has only one responsibility? I can see it does 3 things:

  1. Creates the Validators.
  2. Calls the 2 validators.
  3. Checks the validator resutls.

The problem with this design is that everytime you have a new Validator, you have to create it, call it, and check its return value. This violates the O in the SOLID Principles. (Open / Close)

The form Validator should receive a "custom" List of ICheckable. This "custom" list should also impelment ICheckable so you can just call it. This "custom" List will iterate through its list of ICheckable. That will be it's only responsibility.

Then, The Result has to be evaluated. When a function returns a value, you have to process it. In general this means more code, an extra IF statement. Those two should give you a hint: too much responsibility.

So in order to make this SOLID, you should pass your validators a Callback Interface that will serve to process the validator output. Your sample is quite simple, a validator returns true of false. Which can be represented by two "output" methods - Validated() or ValidationFailed(). O_o, this looks like a very nice "output" interface for your validators and could be implemented by the FormValidator. This design would comply the S. O. L. I. D. of the principles.

Remember, when you first create the FormValidator, you have to create the two Validators, the Custom List and connect everything together.

Then you would be able to unit test all very simple classes, very quickly. (try to start writing your test first)

Note: In general if you tackle the S. Properly, the other principles are very easy to implement.

Hope this helps. Let me know if you need more information.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top