loading...
Cover image for Test Driven Development - not Unit Test Driven Development

Test Driven Development - not Unit Test Driven Development

vladdubrovskis profile image Vlad Dubrovskis ・2 min read

A lot of us in software development would have heard of Test Driven Development. Some swear by it - some hate it and say it is fully unnecessary.

In my opinion people often attribute TDD to the following:

Write unit test -> Red -> Write code to make it pass -> Green -> Refactor

Now although this is one of the approaches that is very common I think the focus is too often given to the lowest level of testing: “unit”.

The practice is called Test Driven Development and not Unit Test Driven Development and a more accurate and common example of flow is:

Test case -> Red -> Write code -> Green -> Refactor

Unit tests are a wonderful technique in our toolbox to help us navigate the problem and keep us laser-focused, but it’s not an antidote to all coding problems. Sometimes in smaller pieces of software it is a lot more valuable and straight forward to write an Integration test first or even an end-to-end test.

Example: In AWS Lambda it is easier to have an end-to-end test that will not only test the result of the function but can catch any permission issues, this is a more likely scenario of something going wrong in AWS world :)

Of course you could argue that what I am describing is Acceptance Test Driven Development (ATDD) - and you would be right. But my main point I am trying to put across: Unit tests are useful when you break down bigger pieces of problem to help find a solution, but at some point the higher level tests are more useful - especially on smaller codebases. For example a small service.

To do Test Driven Development you don’t have to concentrate on “unit” as long as you understand the trade-offs that come with it, for example, less granular feedback of test cases and risk of over-engineering a solution.

One thing for sure: quality and tests are important. Make sure that whatever you do it helps you deploy your code with confidence.

Discussion

pic
Editor guide
vladdubrovskis profile image
Vlad Dubrovskis Author

I have a hypothetical question:

Let’s say you work on a micro service/lambda. You start with TDD and slowly work your way up to higher level tests and application.

As you navigate higher do you end up with all the unit tests you have written throughout or at some point some become obsolete due to integration tests?

My example I have written previously is:

  1. let’s say an endpoint needs to fetch data from other service
  2. I write a test and function that will make http request and give data back
  3. I write test for endpoint that modifies that data from that function above
  4. I write implementation

Depending on how I write the test in step 3, I either mock function from step 1, or HTTP layer again same as in unit test for data function. With latter the unit tests feel like it is obsolete. Yes you probably are losing more granular feedback but then test is better? Plus if I change the function/module in step 1 but data remains same - I don’t have to change tests anymore.

I am still trying to narrow down my exact hypothesis 😀

vladdubrovskis profile image
Vlad Dubrovskis Author

Thanks for your thorough replies Andy - appreciate your time and wisdom :)

I think the last paragraph captures what bothers me the most - when the tests start taking up more time than they should (wonder if there is a measure/metric? everything is 80/20?
😂)

I will think about it a little longer and may come back to this conversation in the future 🙂

Collapse
aleksikauppila profile image
Aleksi Kauppila

but higher level tests tend to cover a much broader scope of functionality, so switching from red->green is probably going to require a much larger amount of implementation, which will hurt the speed of your feedback.

This is so important. Well put. 🙏

Collapse
vladdubrovskis profile image
Vlad Dubrovskis Author

Fair points and fully agree with idea that when starting with something that I know will be quite a big piece of software with a lot of concerns - will opt in for unit level tests to help design separation of concerns and slowly build up the design or blueprint of my solution.

I think will need to come up with a series of examples and try writing different tests to see what works best in certain scenarios.

My main example for integration/e2e tests is Lambda because it usually should be small enough that having unit, integration and e2e tests seems like an overkill.

And often see a lot of tests in a codebase where behaviour is... tested too much? That’s why starting to question certain beliefs I hold.

Thanks for feedback, it’s something I want to write a little more about and need wider input/challenging opinions :)