Just one line of code

I have seen several times that some developers avoid writing tests for small methods or classes. Reasoning behind is familiar: "Just one line of code", "Not necessary", "Time consuming", "It is obvious", "No business logic". I can imagine that this sentence is familiar to many of us.

Indeed, some code piece may look very simple, but does that make it less important?

In order to raise awareness about automated testing in one of my projects, I have conducted a series of sessions to share some context about automated testing, testing pyramid and how simple and helpful unit testing can be. Besides, some developers were feeling uncomfortable with writing integration tests and I have also done some live coding to share my knowledge about more complex integration testing implementations. Writing tests is actually part of way of working, once you get used to it, you can not stop, but if you are not familiar, you may 'postpone' it.

During these sessions, I was still hearing about this "Just one line of code" thing in between. I have searched for something convincing that can challenge the comfort zones. And yes, I guess I found one :)  In one of these sessions I have just started the talk by making a small code change and deploy, "Just one line of code". Here come the details:

Assume that we have a Spring boot application below that serves some data about Songs. If you are not familiar with Java/Spring boot, a brief description for you: Below is a Rest API, accepts GET requests with song id as a path variable. SongController takes the request and forwards it to the SongService without further modifications, takes the response, encapsulates it and sends back to the caller. No error handling or validation is considered yet. Note that, the code is representative, but has nothing to do with that actual code on the project.

Indeed, it does not have complex business logic inside this class and it is true that we have one line of code inside the method. And now let's apply a small change.

Before:

return ResponseEntity.ok(songService.getSong(songId));

After:

return ResponseEntity.ok(songService.getSong(null));

We have just 4 characters of code change above, just one variable in the whole file. Pretty small: "Just one line of code"

And finally I have committed and pushed!

git add SongController.java
git commit -m "Tech Huddle | Ayata | What is null, maybe does not hurt me :)" 
git push

"What is null, maybe does not hurt me :)"

I have continued the talk and at the end came back to the pipeline. Our CI/CD was all green, the application was deployed and seemed to be healthy. However, an essential part of the UI was broken, as the 'song' data was not served anymore.

Good News :) We were not live yet, it was an MVP development phase. And yes, just to make it clear, the bug was intentional to show that it could be avoided.

What we missed here is just a simple safety belt in the pipeline to mitigate the problem. A unit test below could have caught the bug, and would stop the pipeline from going further. i.e.

We have two lines of code for testing:

when(songService.getSong("A123")).thenReturn(new Song("A123", "my song", "rock"));
this.mockMvc.perform(get("/song/A123")).andExpect(MockMvcResultMatchers.jsonPath("$").exists());

One can argue that, for one line of code, there are two lines of test.
Well, if this is time consuming, what about the entities below?

  • The time spent afterwards to test manually if the application works
  • The possible bug fix time
  • The possible damage on user experience

So, either way the testing is done, manual or automated, soon or later, by a developer or a customer. Question here is, early and automated or later and manual? Considering the issues above, the former makes more sense.

Summary

In this post, I tried to highlight how destructive it could be when we miss testing. Yes, the example in this post is an extreme case and it is low probability that a developer will change a parameter to null. Moreover, some languages such as Kotlin does not even allow null assignments by default. However there may be many other cases resulting in similar malfunctioning application, because there is always human factor and testing helps us to mitigate the problems earlier.

Who can guarantee that we won't make mistakes?
How can we create a safe development environment despite our mistakes?

I hope this blog contributes to a good answer.