Implementing the first unit test

Yii provides an empty UserTest class for us, so we're going to start working from there. Head over to tests/codeception/unit/models/ and open the UserTest.php file.

So now our question is: what are we going to implement at this point? Well, the answer will be quite simple, once we've understood what the aim of the unit tests is.

Unit tests, as well as functional and acceptance tests, are a black box testing system: The tests will simply use the interface provided by the object and will make sure that the outputs are as expected. Since the implementation doesn't count if this changes slightly, or even radically, the tests should still pass assuming the interface remained the same.

White box testing, which is provided by code coverage, will instead ensure that we have covered all the possible branches of our code. We will discuss this further in Chapter 8, Analyzing Testing Information.

Tip

Unit tests also provide support for use cases that will document effectively the use of your interfaces to anyone in or outside your team.

So, whether we're starting from scratch, adding new tests, or refactoring some existing ones, we have a few rules to help us achieve as much coverage as possible:

  • Fix the existing broken tests (and raise relevant tickets if not related to our code or if the work ends up being out of scope).
  • Implement tests for the new smallest possible unit of code.
  • Make tests independent from each other.
  • Name tests properly. I've started using long names to understand with accuracy what could be wrong depending on which tests were failing, for example, testMyMethodThrowsAnExceptionWhenInvokedWithNoParameters(); you can clearly use any other naming standards, for instance, using _ as a word separator instead of the camel case; the idea is to keep things readable and maintainable.

We also want to have a few basic rules that could guarantee a 360 degree usage overview so that we can see how to use our component and spot immediately if any of its uses are forbidden, useless, or anything else. These rules are as follows:

  • Cover normal usage of the class/method/whatever (positive test).
  • Cover the extraordinary functionality of whatever you're testing, for example, when it returns the exception (in other words, when it should fail) (negative test).

This might be a bit off-putting, and this first step is possibly the most difficult that I've witnessed, on myself and on my colleagues. Countless times I've seen negative tests missing, creating a huge gap of potential vulnerabilities and fragility in the test.

Don't let yourself down; the reward, as we've seen in Chapter 1, The Testing Mindset, is priceless.

As soon as you start, consider yourself a tester, which is the first and most important step for ensuring the quality of the code that you ship, you can see what you've achieved with an improved sense of confidence in your code.

How much to care for other people's code

Not all the code you're going to test will be the product of your effort.

When working with Yii, we will start testing code or integrations with code that comes from Yii itself, or most likely as in a real-world project, from someone else internally or externally from your team.

Sometimes, it's safe to say that you don't need to test anything that is outside your scope, for many reasons. But, it's also important to understand what the implied risk of not testing these features is.

Think, for instance, about the password verification of the User model, which we will be addressing a few pages further on: the possibility of being unable to verify a saved password is something we need to avoid, as its risk could compromise the overall functionality of our application and have as a consequence the inability of the user to log into our application.

Note

As explained in Chapter 1, The Testing Mindset, and in Chapter 2, Tooling up for Testing, Attributes-Components-Capabilities (ACC) might be something you should be starting to look into if you need this understanding of the risks related to the piece of functionality that you're building.

In our specific case, our tests will be concentrating on bits of functionality provided by the parent class and the interface, such as the following:

  • Validating the User model (this is clearly needed as it's a functionality that is also triggered immediately by the save() method).
  • Saving the User model in the database.
  • Covering the basic usage for the functions we will have to implement from the interface.

It should suffice to say that in some cases, this might fall out of scope. If we were taking into consideration the higher level of abstraction from a BDD point of view, the kind of tests we would be interested in would be the interaction with the User class, as in reading it from the database and how it will be used by other components.

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

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