Chapter 5. Summoning the Test Doubles

In this chapter, we are going to take a close look at test doubles in order to control our tests with more accuracy and avoid having to rely on interfaces we don't know anything about.

We're going to complete the work we started in the previous chapter and understand how to deal with external dependencies, particularly the difference between stubs and mocks.

We will then spend the rest of the chapter on understanding how to organize our tests to improve legibility and maintainability, using some BDD-oriented tools we've introduced earlier in the book, such as Specify and Verify.

On a high level, these are the topics that we will cover in this chapter:

  • Dealing with external dependencies
  • Isolating components with stubs
  • Listening for calls with an observer
  • Writing maintainable unit tests

Dealing with external dependencies

We left our suite of unit tests at an almost complete status. What we had left to cover with tests was the validatePassword() method from our User model class.

The problem that this method is giving us is that we are planning to use our beloved security component, kindly provided by Yii, to encrypt and decrypt the password and verify its correctness. This component is available throughout the life of the application via Yii::$app->getSecurity().

The yiiaseSecurity class exposes a series of methods to help you strengthen your application. The use we will make of it is quite limited, but I would recommend reading a bit more about it on the official documentation available at http://www.yiiframework.com/doc-2.0/guide-security-authentication.html and the following sections that will cover all aspects of authentication, encryption, and so forth.

Let's then define how we think our implementation should work for this method. The documented use for validating the password is the following:

public function testValidatePasswordReturnsTrueIfPasswordIsCorrect() {
    $expectedPassword = 'valid password';

    $this->_user->password = Yii::$app->getSecurity()->generatePasswordHash($expectedPassword);

    $this->assertTrue($this->_user->validatePassword($expectedPassword));
}

This means that we will need to create the password hash first by using the aforementioned helper class, set it in the user, and then can use the $user->validatePassword() method to check whether the actual cleartext password that is passed matches the internal one. Some sort of encryption/decryption should happen behind the curtains, ideally by using Security::validatePassword() from the security component.

A possible implementation of User::validatePassword() in the user model can be the following:

// models/User.php

/**
 * Validates password
 *
 * @param  string  $password password to validate
 * @return boolean if password provided is valid for current user
 */
public function validatePassword($password)
{
    return Yii::$app->getSecurity()->validatePassword($password, $this->password);
}

If we try to run the tests, this specific method will pass without problems.

This might be a good solution, but we need to be extremely conscious that this is not a true unit test; it's more of an integration test, as we still have the dependency on the security component.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset