Unit Testing XIV – Dependency Injection in the User Class

Adding Dependency Injection to the User class


In the previous article in this series, we saw the T4_UserDependencyInjectionTest code. In this one, we'll look at its associated User class file: User4.class.php.


MODX logo

User4.class.php

Here's the code (also available at GitHub, here):

<?php

    class User4 {
        protected $errors = array();
        /** @var Validator $validator */
        protected $validator = null;
        protected $fields = array(
            'username' => '',
            'email' => '',
            'phone' => ''
        );

    function __construct($validator, $properties = array()){
        $this->validator = $validator;
        if (!empty($properties)) {
            foreach ($properties as $key => $value) {
                $this->set($key, $value);
            }
        }
    }

    public function set($fieldName, $value) {
        $errorMsg = '';
        switch($fieldName) {
            case 'username':
                $valid = $this->validator->validateUsername($value);
                $errorMsg = 'Invalid username';
                break;

            case 'email':
                $valid = $this->validator->validateEmail($value);
                $errorMsg = 'Invalid email';
                break;

            case 'phone':
                $valid = $this->validator->validatePhone($value);
                $errorMsg = 'Invalid phone';
                break;

            default:
                $valid = false;
                $errorMsg = 'Unknown field';

        }
        if ($valid === false) {
            $this->addError($errorMsg);
        } else {
            $this->fields[$fieldName] = $value;
        }
        return $valid;
    }
    public function get($fieldName) {
        if (array_key_exists($fieldName, $this->fields)) {
            return $this->fields[$fieldName];
        } else {
            $this->addError('Unknown Field: ' . $fieldName);
            return null;
        }
    }

    public function save() {
        return true;
    }

    public function addError($error) {
        $this->errors[] = $error;
    }

    public function getErrors() {
        return $this->errors;
    }
    public function clearErrors() {
        $this->errors = array();
    }

    public function hasErrors() {
        return !empty($this->errors);
    }
}

Changes

The changes are pretty minimal. We've removed the require_once at the top that includes the Validator class. Since we are using Dependency Injection and passing an instance of that class as a parameter to our User class constructor, we no longer need to include it.

We've changed the first two lines of the constructor from

function __construct($properties = array()){
        $this->validator = new Validator();

to

function __construct($validator, $properties = array()){
        $this->validator = $validator;

adding $validator as the first parameter in the first line, and setting $this->validator to it in the second.

In the set() method, we've changed all three validation lines from this form:

$valid = $this->validateUsername($value);

to this form:

$valid = $this->validator->validateEmail($value);

Thanks to the dependency injection, we no longer need to call the three separate validation methods. Since they're contained in the Validator class, we can create stubbed versions of them in the $validator we pass in.

The final change is to remove those three validation methods from the User class code because we no longer need them.

You might have thought of making the three validation methods in the Validator class into public static functions. This would allow us to call them without instantiating a Validator object with calls like this: Validator::validateEmail(). The problem with that approach is that static methods can't be stubbed or mocked without resorting to third-party test-double packages like Mockery or Phake.


Coming Up

In the next article, we'll look at testing expectations with mock objects.



For more information on how to use MODX to create a web site, see my web site Bob's Guides, or better yet, buy my book: MODX: The Official Guide.

Looking for high-quality, MODX-friendly hosting? As of May 2016, Bob's Guides is hosted at A2 hosting. (More information in the box below.)



Comments (0)


Please login to comment.

  (Login)