Learning Test Driven Development — A experience-based narrative

Gaurav Edekar
Blue Harvest Tech Blog
7 min readNov 22, 2019

--

Before I knew about “Test Driven Development”, the only testing I had done was “manually” test the code that I had written to ensure that it worked. Then we would rely on the Quality Assurance team to find problems for us.

And, they did much to our dismay.

Our “Scrum Master” & “Project Manager” even planned bug fixing as the last two days of the two-week sprint. Because the quality of the code was important for all of us.

The first time I heard the words “Test Driven Development” when I was asked about it in an Interview. I prepared a short paragraph to talk about it since my consultancy manager gave me a hint that the client is inclined towards hiring people who know about this term.

I had not done TDD before that, but reading about it that day was thought-provoking. The articles that I read said that knowing about what the code should do before writing the actual code guarantees that this is what you expect the outcome to be when you implement the code.

This was something I had never thought about before.

The only that I had thought about what the code should give me was usually after writing the code. This I understood later was the basis of TDD, if you already set an expectation about what you want to do, then it’s easy to validate what you have done.

In a world without tests, we would verify what it does by building the code, run the application and then test the functionality. This process “write code”, “build code”, “run application” and then manually test, is a repetitive process is called as a feedback cycle.

It was a “long feedback loop”.

This was the “first” thing I learned from TDD. A longer feedback loop in the development process is tiring, if its too long then a developer will be tired at the end of the day. And stress is equal to mistakes is equal to buggy code. An overshare, the applications which I tested manually in my early days used to take 9 minutes to startup (That’s right, we had lots of coffee breaks)

Test-Driven Development gives the developers a shorter feedback loop.

Often, we developers forget all the requirements of the piece of code that we are building. So we need to look at the “Jira” story or documentation that describes those requirements. Then if you satisfy one requirement and at the time of satisfying the second requirement, you could break the code that satisfies the first one.

If you have tests, then every time you update the code you can run tests for that piece of code. Now you have a safeguard because the moment you break the requirement number one, you see the test for it is failing immediately, and not when the QA is testing the whole thing.

On top of the safeguard, if you have failing tests already stating the expectations from code beforehand, then you don’t need to read your story documentation every time you write code for each requirement.

Photo by Artem Sapegin on Unsplash

The second thing I learned was, the tests are safeguards to the code. They fail the moment you break code, given that you run them every time you change code (and build it).
And the third thing, the tests are upfront documentation of the requirements you are supposed to satisfy. The moment you run the tests and they are passing you know you have nailed it.
The next step is to talk to the QA, add more tests for the tricky situations they suggest (or if they come back with a surprise bug later, add a failing test for that bug).

If you reflect on the two things above then you will notice that they are contributing to the faster feedback cycle. That gives us quicker detection of bugs, quicker responses to changes, as soon as we change the code and run the build.

So after that, I started writing tests for the code I was writing. I was doing a lot of feature additions to a legacy system. It was fun, a cool senior developer set up annotations for the Oracle Commerce application that we were working on and now we had live integration tests (which ran the application). We had started releasing weekly by that time thanks to CI-CD set up by our teammates.

Next came greenfield applications.

We were creating new Microservices. We were driving the development in a test-driven way.

We would write tests and then write code inside the classes, run the tests. Refactor the classes, run the tests again. This was the Red-Green-Refactor cycle of TDD.

We were safe on fulfilling the requirements & doing fewer bugs. But, there were other issues too. Like we missed out on the user perspective like good error messages.
Then I found out that the whole design of the system could be driven in a Test Driven Way. It means that you can drive the design of the system through Test-Driven Development.
To test the concept of Test Driven Design I created an application 99% TDD, I quickly found out that you need a map to look at even when doing TDD.

The fourth thing I learned, it is possible to drive the system design using TDD, but you need to visualize the Big Picture, use the whiteboard.

Then write tests for building the components from the System Design on the Whiteboard.

I am still learning TDD. I suppose I have to gain more experience on how exactly Test Driven Design is done, that is how the whole system could be designed starting with a test if that is the right way I look at it. As of today I prefer talking to the teammates and whiteboarding the system design together first and then implement it in TDD style.

There are a few practical situations that I think we developers should reflect upon, after becoming a bit familiar with the process of TDD.
If you have to do a Proof Of Concept, get started with something quickly, then I would recommend to just do it. If that first step works or if your POC was accepted, then do the whole thing with proper tests and refactoring.

There have been times I got bored writing tests for something that I was purely trying out, like a new framework. I needed to get it up and running to do the first step.
If it's a Plain Old Java Object, then I wouldn’t want to write tests unless a method inside the POJO does something with a lot of IF conditions (if you are encountering this then you have violated the SRP, let’s talk about it another day)

If it’s a pure framework construct then you don’t need to write tests, the framework should do what is expected of it. So for example, if you wrote a test to check whether the @Autowired annotation in your spring application wires an instance, then you are doing something unnecessary.

There are exceptions to this exception too.

Photo by Daria Nepriakhina on Unsplash

In one project, we were learning the API for a Payment Provider, to understand their API, we wrote a lot of integration tests that talked to their test sandbox. They would be termed learning tests. The first thing we did to get started was to do a simple connection test and then proceeded to learn the API by understanding the objects that they needed & methods that they suggested to be invoked.

In this case, the tests helped us to learn something. And that’s the fifth thing I learned from TDD. It is a really good tool to start learning something new on a small scale. Usage of TDD to learn new things falls in place naturally by starting small and consequently failing small.

If we look at the words “failing small” from the last sentence, that is the next thing to learn, TDD breaks down the whole code into small independently tested parts. So when something fails, it shows that only that small part of the code is failing. We know exactly the region where things are going wrong, and that makes us developers and testers feel more secure as compared to seeing a bug when the application is running and having no idea where it came from.

To Summarize:

  • Test-Driven Development gives shorter feedback loops
  • Tests guard against new bugs in existing features (think about, change code — run tests — repeat)
  • Tests serve as living documentation for the basic requirements that code should satisfy
  • TDD can be used to drive the system design (but the team members must talk to each other & do the system design on a whiteboard)
  • TDD is a great tool to learn something new, be it a new API or even a new programming language

Having said all these, we developers & testers need to always empathize with the end-user when solving a problem. Because, no matter how many tests we write or how clean our code is, it would be of no use if the end-users are not getting what they want from our software.

--

--

Gaurav Edekar
Blue Harvest Tech Blog

Learning how to learn, writing code every day, making nice food, running, cycling, swimming, love Starcraft and dream of doing a presentation in Swedish