Why you should ‘code’ before you actually code

Fijar Lazuardy
Inside PPL B7
Published in
5 min readApr 13, 2020

TDD, or Test Driven Development in full, is not a new concept in modern software development practices. However, many software engineers still find it very weird and contrary to common sense. In this brief article, I will try to clarify the TDD concepts and prepare your mindset to start TDD from today.

What is TDD?

Contrary to popular belief, TDD is not a testing process. It is a design process. It’s a robust way of designing software components interactively, one unit at a time, by making sure that the individual component’s behavior is specified through unit tests beforehand.

TDD Principles

By combining programming, unit test writing and refactoring, TDD is a structuring practice that allows to obtain a clean code, easy to modify and answering the expressed needs which remains the first priority when developing an application. The TDD has 3 phases:

  1. RED. First write a unit test in failure. The impossibility of compiling is a failure.
  2. GREEN. Write as soon as possible the production code sufficient to pass this unit test even if it means allowing the “worst” solutions. Of course if a clean and simple solution appears immediately, it must be realized but otherwise it is not serious the code will be improved incrementally during the refactoring phases. The aim here is to obtain as soon as possible the green bar of success of the unit tests.
  3. REFACTOR. This phase is often neglected but is essential because it eliminates possible code duplications but also makes it possible to make changes in architecture, factorization, presentation… This refactoring concerns both the production code and the test code and must not modify the external behavior of the program, which is materialized by a test execution bar that remains green.

Types of Test

  • Unit testing — is the level of testing that checks individual units (components) of our code in isolation from others, purpose is to ensure each unit of the code functions as designed.
  • Integration testing — is the level of testing that combines units as a group and tests how they work together, purpose is to expose the faults that might exist in the interaction individual units.
  • End-to-End testing — is the level of testing that checks the flow of a system from beginning to end as a single application and that it behaves as expected, purpose is to identify system errors and strengths and to ensure that the data on the system is secure across all levels of the system.
Figure 1: TDD lifecycle

Wait, i suppose to fail my code?

Yes, you should. In the RED phase, you literally write a failing test, so that you know exactly how your function is suppose to behave. It will help you write a code that fulfill your need, and easier to debug as well without being afraid messing your code.

Example

Okay, now, let’s get our hand dirty.

Suppose we want to make a Javascript function, and we want to make a unit-test for it. Let’s call the function sum, it takes two parameter, a and b, and will return the sum of it. We’re gonna make the test, write the function, then run the test to test our function.

To be able to perform all tests below or even write your own tests, you need to setup your environment for that.

// In your terminal do the following
$ npm init
$ npm install --save-dev jest// Then in your package.json file
// change the value of test in scripts to jest
{
"scripts": {
"test": "jest"
}
}

I’m gonna give a quick explanation about Jest expect Api.
The Jest expect Api has a number of matchers you can use, It looks like Jest already accounted for all the things possible to be tested, you can test for truthiness, numbers, objects, arrays containing certain values, and much more. When you’re writing tests, you often need to check that values meet certain conditions. expect gives you access to a number of "matchers" that lets’ you validate different things. We obviously can’t talk about all the matchers or methods possible, we will however talk about .toBe() , .toMatch() , and .toEqual() . To learn more about expect visit the Jest expect Api documentation page.

Okay, now let’s write our test

const sum = require('./sum') // assuming name of file will be sum 
// and they are in the same directory
test(‘Add 1 and 2 to give 3’, () => {
expect(sum(1,2)).toBe(3);
});

Okay what’s going on here? It’s simple, first we import the function name (assuming the name is sum and it is placed in the same directory). And the first test we want to write is if we put 1 and 2 as parameter, it should return 3 as the result, so we’re using the function expect to compare the result of sum(1,2) and 3 using toBe(), and it supposed to be the same. Now if we run the test, it will fail, of course, cause we don’t have the sum function yet. Now let’s create the function

function sum(a, b) { 
return a + b
}
module.exports = sum; // so we can import it in the Jest file

Now if we run the test, our test will pass for sure. And that’s it, that’s one of approach of implement TDD.

Coverage

Imagine you’re having a pretty big application, one of the way to know if you’ve written a good amount of tests is by see the coverage of your app. I won’t cover much about this, but let me show an example.

Imagine this is our app. We have written a bunch of tests, but when we see the coverage, it hasn’t covered all of our code. You should strive for 100 but do not kill yourself in the process (i.e. do not wast valuable time), there are more things to do than trying to hit 100 but before you stop trying to kill yourself make sure you hit a 92% at the least.

And, after bunch of refactor and more coding, our coverage then become

And by that, we have make tests all of our code in our app, and our app should’ve less bug, and can be easily refactored.

I think that’s all you need to know first about TDD, any feedback will be appreciated, Happy coding! :)

--

--