This article opens a whole category about test-driven development (TDD). It will be covering questions that arise during this practice and observations… like this one.
What is this all about?
The basic idea of TDD is to write tests first, then code. You write the simple code that fails, then make it pass and repeat.
But the “simplest” here tends to be confusing. What should be considered to match this parameter? The simplest implementation of the whole algorithm? Well, no.
The minimum code that fails
The less code you write in your tests, the better. And this also applies to the simplicity part. You can consider that test fails if it does not compile or crash or (finally) assertion does not pass.
That means the simplest code that fails is one that does not compile. You try to instantiate an instance, but the type has not been defined yet - test failing. You try to call a method that does not exist yet - test failing.
The process of writing a test is that simple and that fast has iterations between writing test and real code: add parameter in the test – fail – update the real code.
The real code uses the same idea
The “simples code” is also applied to the real code part. You write the minimum, the most straightforward code, that make your test green. And here, often, it gets confusing. Let me illustrate.
def test_pow_zero():
resut = pow(0, 2)
assert(0, result)
We expected 0*0=0
with the code above, which is pretty obvious. This is our first test for the pow
function. Now we need to write the code to pass the test. What should it look like?
def pow(base, exp):
return 0
If this is surprising for you, do not be upset. You need to hack your mind first to get comfortable with that idea. You do not need to make the entire solution for the first test to pass, “zero” will be just enough.
Then, as you proceed, you will write the next test, for example, for 1*1=1
:
def test_pow_one():
resut = pow(1, 2)
assert(1, result)
The test fails because we always return 0. Let’s modify:
def pow(base, exp):
return x
Both tests now passing, right? Finally, we cover one more case here for 10:
def test_pow_ten():
resut = pow(10, 2)
assert(100, result)
And the modification of the real code will be
def pow(base, exp):
return x * x
Everything is passing, and we’ve already covered 3 cases.
You might say “This is a too simple case, and the pow
can be written without any tests!”.
The key purpose is to illustrate the amount of real code we need to pass the test.