Unit testing is the act of testing a unit of code. A unit is often a function or a class method. The purpose of each test is to verify the proper behavior of the unit being tested.
Unit tests are not integration tests. Unit tests are "low-level" and very focused.
Validation: A unit test verifies a method is functioning properly.
Maintainable code: Unit testing forces a developer to write with testability in mind. Testable methods are concise, has one well-defined purpose, and is loosely coupled.
Documentation: A unit test serves as a concrete example how a method is used, what its inputs and output are, and how it behaves - a picture (usage example) is worth 1,000 words.
Professionalism: Instills value of quality; mindset turns from "test bugs out" to "build quality in."
Slow down in velocity: writing tests is extra effort (may need to re-groom tasks with this effort in mind).
Better organization/maintainability: unit testing encourage shorter methods and better encapsulation/isolation. it promotes the principles of Single Responsibility, Interface Segregation, and Dependency Injection.
Less preventable bugs delivered to QA: less back-and-forth on tasks.
The canonical form of a unit test is:
1. Set up preconditions for the method to be tested.
2. Invoke the method exactly once, passing in the values established in step 1.
3. Make assertions about the return value and any side effects.
… Do absolutely nothing else.
A unit test verifies only one thing: a unit test for a method is only concerned with testing code that lives in the method body itself.
A unit test tests code in isolation: isolation reduces the number of factors that can affect test results and makes it easier to determine whether the unit is correct.
* No network access
* a test must avoid coupling with other tests or parts of the system for which it's not responsible for testing
* mock objects and stubs are used to eliminate dependencies
* the application becomes an implicit integration test of all the units
Code with its tentacles everywhere is not testable: Classes that instantiate other classes, nested method calls like a matryoshka doll, etc. cannot be unit tested. They need to be refactored.
Methods should be simple as possible: Methods should do one thing. Break up complex logic and test the components on their own. Otherwise, if a test fails, how do you pinpoint the break?
One must know what good code is before he can refactor bad code:
* Single Responsibility – An object should do one thing and one
thing only, and it should be the only object in the codebase
that does that one thing.
* Interface Segregation – Separating contact points by interfaces
makes it easy to substitute concrete classes with mock objects
and stubs.
* Dependency Injection – Injecting an object's dependencies
through a constructor or setter-method decouples it from other
concrete objects.
… Encourage participants to read up on SOLID
Problem: $_SESSION
Fix: pass value to method when called
Problem: DB queries
Fix: move to model class, update method to receive instance of model
Filtering is iffy – Is the method doing too much?
… But at least it’s testable now.
Create an interface with the model’s methods. The model implements the interface.
A test model implements the interface and returns known data.