There are as many kinds of tests there are names for them. However, there are three useful classes of tests that I will cover
Unit tests tests the smallest possible part of the system. This could be a function which determines if a license needs renewal. This implies that unit tests do not touch the database.
Integration tests tests the boundaries between classes. Integration tests may rely on the database, multiple classes and so on. They strive to make sure that a specific feature is working. This could "Does User::getById work?".
System tests invoke the whole system by invoking commands through the UI, as well as making assertions about system state on public side effects.
Like test.php
, except you save it to preserve your assumptions.
If you use tests to create new features on a system, you should consider true TDD:
- Write the smallest possible test to get an error
- Write the smallest possible amount of code to remove or change the error
- Refactor (DRY)
This is by far the easiest, as you have control over the design. Make vertical slices of functionality.
If this is the state you are in "Growing object oriented software, guided by tests" by Steve Freeman and Nat Pryce should be your go to guide.
If you inherit a system, you might want to get it under test. Here, the task is to systematically describe what the system does, such that refactoring becomes safer.
This is super hard. The chicken and hen problem quickly arises: "I need to change the code to get it under test", "I need to get the coder under test so I can change it".
If this is the state you are in "Working effectively with legacy code" by Micheal Feathers is the go to guide.
Often people will find it hard to test. First the struggle which how to test, then they struggle with maintaining the tests they have written.
Often the question arises how to test features. Sandi Metz gives us the answer: Look at what kind of message you are sending to the object: http://www.youtube.com/watch?v=URSWYvyc42M
(In, Self, Out) x (Query, Command)
In production code we want methods to be fast to write, so we often trade more descriptive names for shorter, more easy to write. In tests we want them to be as descriptive as possible. If we cannot easily decipher what a test tests, it is useless. Try to define a DSL in your tests by using builders.
We should do everything in our power to keep the tests as clean and easy to maintain as the production code we write.
- Learn your tools, for PHPUnit, this is a good start: https://jtreminio.com/2013/03/unit-testing-tutorial-introduction-to-phpunit/
- Being good a object oriented design is very helpful, read "Clean Code" by Robert C. Martin (Uncle Bob)
- Practice testing deliberately. Write "just for fun" code as an exercise to get a hang of it.
- Read books and blogs, you can invent the tricks yourself, it is just much harder.
Link to quick 5 min. video about testing: http://www.littlehart.net/atthekeyboard/2012/08/16/5-minute-tdd/