4. Here’s The Basic Workflow
Write a test that fails Make it pass
Start Here
5. Here’s The Basic Workflow
Write a test that fails Make it pass
Refactor
Start Here
6. A replacement for a good high level design.
TDD Is NOT
TDD is bottom-up by nature which makes it hard to see the big picture.
NOTE: Many people will disagree
with me on this one!
Also sometimes by starting with a high level architecture
I can leverage existing knowledge, this is why frameworks like QT exist.
7. The same as unit testing
TDD Is NOT
TDD is a workflow, You use unit tests as a tool to drive your design
and ensure that you’re on the right track.
Unit tests can be (and are) used outside the scope of TDD.
It is true however that writing good unit tests on existing code is very hard.
8. A replacement for your QA
TDD Is NOT
Unit tests are simply not enough, There are also Usability Tests
Integration tests, Performance tests etc…
9. The 3 Rules Of TDD
1. You are not allowed to write any production code unless
it is to make a failing unit test pass.
10. The 3 Rules Of TDD
1. You are not allowed to write any production code unless
it is to make a failing unit test pass.
2. You are not allowed to write any more of a unit test than
is sufficient to fail.
11. The 3 Rules Of TDD
1. You are not allowed to write any production code unless
it is to make a failing unit test pass.
2. You are not allowed to write any more of a unit test than
is sufficient to fail.
3. You are not allowed to write any more production code
than is sufficient to pass the one failing unit test.
12. Wait, What’s a Unit Test?
Code that tests certain behavior in an isolated component.
def test_covert_red_from_RGB_to_HSL(self):
redHSL = [0, 100, 50]
self.assertListEqual(redHSL, rgb2hsl(255,0, 0))
def test_start_car_with_no_gas_should_throw_error(self):
emptyGasTank = FakeGasTank()
car = Car(emptyGasTank, FakeEngine())
emptyGasTank.gasLeft = MagicMock(return_value=0) # new in python 3.3
self.assertRaises(CustomError, car.start)
13. Remember, It’s NOT A Unit Test If
● It touches the file system or the DB (read || write)
● It communicates across the network
● It can’t run in parallel with other unit tests.
● It contains randomness, (i.e different each time you run it).
● It requires you to modify the environment (edit config etc…)
● It doesn't contain an assert statement.
14. Anatomy Of A Unit Test
class TestAssetLoader(unittest.TestCase):
...
def test_should_only_load_assets_once(self):
fakeFileReader = FakeFileReader()
assetManager = AssetManager(fakeFileReader)
assetManager.getImage("kozet_the_sheep")
assetManager.getImage("kozet_the_sheep")
self.assertEqual(1, fakeFileReader.load.call_count)
...
15. Anatomy Of A Unit Test
fakeFileReader = FakeFileReader()
assetManager = AssetManager(fakeFileReader)
assetManager.getImage("kozet_the_sheep")
assetManager.getImage("kozet_the_sheep")
self.assertEqual(1, fakeFileReader.load.call_count)
Arrange
Act
Assert
Arrange Act Assert (AAA) Pattern
16. Fakes (Mocks, Stubs, Spies)
Fakes Are Basically Used To:
1. Isolate the component under test from the rest of the system.
2. Inspect the effects on the outside world.
17. Fakes (Mocks, Stubs, Spies)
● Stub is just a dummy object to fill the role of a real object.
● Mock is a stub with an assert condition inside.
● Spy is just a wrapper that stores info like number of calls, parameters etc...
Here’s a simple way to think about them:
Most of the time when people say mock they actually mean stub.
But it’s not important as long as you don’t use no more than 1 real mock in a
test.