Test Driven Development
If it's worth building, it's worth testing
- I already know it works!
- Others who work on your code in the future won’t know if they broke something
- I don’t write broken code!
- Sometimes the environment changes and other future libraries read your code
- I have no time!
- Testing actually saves you time (and stress) in the long run
A level of the software testing process where a system is tested for acceptability. The purpose of this test is to evaluate the system’s compliance with the business requirements and assess whether it is acceptable for delivery.
A level of the software testing process where a complete, integrated system/software is tested. The purpose of this test is to evaluate the system’s compliance with the specified requirements.
A level of the software testing process where individual units are combined and tested as a group. The purpose of this level of testing is to expose faults in the interaction between integrated units.
A level of the software testing process where individual units/ components of a software/system are tested. The purpose is to validate that each unit of the software performs as designed.
Behavior-Driven Development (BDD)
- Describes the behavior of the system from the outside in
- Used for Integration / Acceptance Testing
Test Driven Development (TDD)
- Tests the functions of the system from the inside out
- Used for unit testing
Cycle: ... -> RED -> GREEN -> REFACTOR -> ...
- Write a test case and watch it FAIL
- Write the code to make it PASS
- REFACTOR the code to make it great knowing that the test case will let you know if you broke anything
BDD & TDD
"BDD is building the right thing, and TDD is building the thing right."
- Test Driven Development means that your test cases drive the design and development of your code
- You write the tests first for the code you wish you had, then you write the code to make the test pass
- This keeps you focused on the purpose of the code (i.e., what is it supposed to do)
- First and foremost it saves time when developing!
- It allows you to run faster because you are more confident
- It insures that your code is working as you expected
- It insures that future changes don’t break your code
- In order to use a DevOps Pipeline, all testing must be automated
- Run fast (they have short setups, run times, and break downs).
- Run in isolation (you should be able to reorder them).
- Use data that makes them easy to read and to understand.
- Use real data (e.g. copies of production data) when they need to.
- Represent one step towards your overall goal.
- Write a failing unit test for the code you wish you had
- Write just enough code to make the unit test pass
- Refactor the code and repeat
A test fixture is a fixed state of a set of objects used as a baseline for running tests.
The purpose of a test fixture is to ensure that there is a well known and fixed environment in which tests are run so that results are repeatable.
Examples of fixtures:
- Preparation of input data and setup/creation of fake or mock objects
- Loading a database with a specific, known set of data
- Copying a specific known set of files creating a test fixture will create a set of objects initialized to certain states.
def setUpModule(): # runs once before any tests
def tearDownModule(): # runs once after all tests
def setUpClass(cls): # runs once before test class
def tearDownClass(cls): # runs once after test class
def setUp(self): #runs before each tests
def tearDown(self): # runs after each tests
- Mocking creates fake objects that behave like the real thing
- Any external service that is not under test should be Mocked
- Sometimes you need to change the behavior of a dependent system under test
- Maybe you don’t have a remote connection to another component
- Or you want to isolate your tests from a remote component
- Patch: This patches a function call allowing you to change it’s behavior
- MagicMock: This mocks an entire object changing it’s behavior. Usually used as a return value
Sometimes you will need fake data to test against, sometimes you will want an entire class to be fake data, Factories and Fakes make this possible. We will use Factory Boy in Python for this.