What Are the Challenges When Starting to Implement Tests

When can test-writing become hard?

Itchimonji
CP Massive Programming
6 min readFeb 2, 2022

--

Photo by Towfiqu barbhuiya on Unsplash

These days for your applications, a decoupled and encapsulated software system is ever more relevant. Reusability, maintenance, care, and sustainability play a major role in our software development projects — they are getting bigger and bigger.

But how can we ensure sustainability, reusability, and quality?

One option would be to use tests or a high test coverage.

Product owners very often wonder why some developers do not write tests or even want to write tests. Here are some reasons I have already come across:

Mindset

For many developers tests are not part of software development: Testing only costs time that would be much better spent on developing features. The Quality Department will find the necessary errors. And besides, you could test by hand.

I think this is wrong.

In the long run, testing even saves time, because many feature developments also involve adapting, correcting, or improving existing code. How do you know that everything still works the way it did before the changes? Maybe by testing it — but with automation and not manually.

And we should not pass on the responsibility for the quality of a product to other employees or departments. We are responsible for our code and its quality and we should keep it that way.

Missing Knowledge About the Importance of Tests

Developers change code permanently. Reasons are: adding a feature, fixing a bug, improving the design, optimizing resource age, or update dependencies. But how can we ensure that the new changes have not caused any bugs?

Changes in a system can be made in two primary ways. I like to call them “Edit and Pray” and “Cover and Modify”. Unfortunately, “Edit and Pray” is pretty much the industry standard. When you use “Edit and Pray”, you carefully plan the changes you are going to make, you make sure that you understand the code you are going to modify, and then you start to make the changes. When you’re done, you run the system to see if the change was enabled, and then you poke around further to make sure that didn’t break anything.” — Michael C. Feathers [Working Effectively With Legacy Code]

Not very professional, is it? Covering software means covering it with tests. So, developers can make sure they did not break anything in the software product with their changes.

With tests as a safety net, software engineers can implement new changes very quickly, ensure that existing code is not broken and that no bugs blow up in the user’s face.

Lack of Knowhow for Writing Testable Code

Sometimes developers just can not manage to write a clean and simple test, or spend a very long time on generating a test at all. This can have different reasons: maybe it is hard to create the object instance without using hard dependencies (e.g., real databases); or a function they want to test has too many concurrencies; maybe the code is not decoupled enough; sometimes developers do not know all dependencies of the instance; and so on.

There are many principles out there describing how to write testable code. Kent Beck, Robert C. Martin, Michael C. Feathers, and many more great authors wrote a multitude of good books about this. It is worth taking a look.

Time

Saying that tests simply cost time is not wrong. But they also save time, and above all, frustration. Everybody knows the long sessions, when a developer needs to find a bug and does not get it. What could happen if there are tests for the code? Would such tests be shortened or spared?

Who knows — but with tests around the code, nailing down functional problems often is easier. And for the long run, having tests as a safety net, as described above, software engineers can implement new changes very quickly and ensure that existing code is not broken.

Legacy Code

Very often developers do not want to test code that they did not write or that is outdated (keyword: legacy code). But what is legacy code? Legacy code is simply code that has no tests and so no one knows what it is doing or new changes make it impossible to detect if anything broke.

“Code without tests is bad code. It doesn’t matter how well written it is; it doesn’t matter how pretty or object-oriented or well-encapsulated it is. With tests, we can change the behavior of our code quickly and verifiably. Without them, we really don’t know if our code is getting better or worse.” — Michael C. Feathers [Working Effectively With Legacy Code]

Often it is very hard to write tests, especially when implementing code you see for the first time. Some code you’ll find is also absolutely untestable and must first be made testable by refactoring it in order to increase decoupling, reusability, and maintainability. But please do not confuse refactorings with rewrites.

The First Test Is the Hardest

Often, a developer is completely new to a testing framework (like Jest, JUnit, or others) or new to a project and needs to find their way how to actually write unit tests with/in it.

This can often lead to frustration or refraining from writing tests completely. But I believe it is worth doing, because all subsequent tests will become easier and easier to implement. And at some point you will be writing tests with absolute precision, passion, and speed.

After all this, you feel very comfortable in the new project or test framework and you can ensure the quality of your code with comprehensive tests.

Unknown Benefits for Developers

Some developers do not know the benefits of writing tests:

  • Writing better code: decoupled, encapsulated, sustainable, reusable, reliable, and readable
  • Catching and validating defects easily at an early state
  • Simplifying debugging
  • Fast implementation of new features by getting quick feedback of working code
  • Reducing code complexity
  • Allowing code refactoring and design improvement following Martin Fowler’s example
  • Speeding up the process with less effort in manual testing
  • Reducing costs by avoiding fixing bugs at a late state (e.g., production)

Missing Infrastructure for Testing (CI/CD)

Sometimes it is really hard to write tests when you are not given an infrastructure. Especially for end-to-end tests this would be very useful. A database that automatically resets itself or creates a state that is needed for a certain test.

With CI/CD pipelines you can already achieve a lot and provide desired states or environments. These are automatically started up and shut down again — also known as nightly tests.

Databases can be set to a desired state with ready-made scripts. Backend or microservices can assume a desired state. And the frontend can be redirected to a specific URL.

After the end-to-end tests have been run, the environment can be easily shut down and rebooted to another state in order to run other tests.

All this is possible with Infrastructure as Code (IaC):

Conclusion

Testing helps the developer to minimise long-term entropy, to find bugs early, and to ensure customer satisfaction. Many developers look for excuses not to test: the wrong setting, no time, ignorance, or laziness. However, a high test coverage brings many advantages to the product. There are now a lot of knowledge, frameworks, and approaches available for simplifying testing. I roughly described these in this article.

Maybe one or the other is just lacking the right motivation and I hope that through this article, I have awakened your interest a little.

I hope I could inspire you to test more now.

Follow me on Medium, or Twitter, or subscribe here on Medium to read more about DevOps, Agile & Development Principles, Angular and other useful stuff. Thanks for reading and hopefully you can use this article in the near future. Happy Coding! :)

Learn More

Resources

--

--

Itchimonji
CP Massive Programming

Freelancer | Site Reliability Engineer (DevOps) / Kubernetes (CKAD) | Full Stack Software Engineer | https://patrick-eichler.com/links