If you are like me, you probably write a lot of tests for your production code. Tests verify our business logic and make us confident that our code is still correct after making changes. But what if I told you that this leads to many problems in the long term? Of course, we don't want to avoid writing code tests, but we often have an issue called Structural Coupling.
Structural coupling makes refactoring our code very difficult, and it costs us a lot of time and money! But there is one solution: a Testing API. It's an API with superpowers that helps you to get rid of this structural coupling. At the same time, you are still able to verify your business rules. So a Testing API does save you not only time but also money! That's why today I want to answer the following questions:
This article will be part 1 of a series for analyzing the Testing API. So let's go!
The concept is not new. Robert C. Martin introduced this concept in his book Clean Architecture for the first time. The main goal is to break structural coupling between your production code and your test code.
What does this exactly mean? In the object-oriented programming paradigm, when we write code tests (unit, integration, etc.), we want to verify the functionality of a specific class or method. Ultimately, we want to make sure that future changes don't break the current functionality. Therefore, we tend to write one test class for one production class and one or more test methods for every production method. Especially at the beginning of the development process, this is a reasonable thought and is no problem at all.
When your application grows, it gets more complicated over time. You might be able to do minor refactorings within classes or methods but completely changing or dividing the structure of your application becomes a problem. It is possible, of course, but then you need to change the design of your test classes and test methods. And this is structural coupling!
Coupling the structure between your test code and your production code is not bad per se. Sometimes we even want this kind of coupling when writing unit tests. However, the tests written via a Testing API are not a replacement for unit tests. Instead, they are automated use-case-driven tests (system tests), and thus they are more like end-to-end tests without a UI.
Especially at the beginning of the development cycle of a new app, we often have unclear business rules or use cases. So having fuzzy business rules also increases structural coupling. In this case, the Testing API gives us another layer of abstraction. We extend the API whenever you add new business rules. The API gets all the necessary production code and provides one single API for your tests.
One significant advantage is that by extending your test suite with tests that use a Testing API, you gain independence from the structure of your production code. You only care about the use-case scenarios and the business logic, verified through your tests (system tests). If you need to refactor several components of your production code, your tests that use the Testing API should still be valid. It gives you also higher flexibility for your refactoring efforts.
Looking at the angle of end-to-end tests, we can use those automated use-case-driven tests to verify our business logic. Compared to regular end-to-end tests where we also include the user interface, testing via a Testing API is faster and more lightweight. And we can find issues within the UI faster due to those use-case-driven tests.
As with every concept, there are, of course, some drawbacks as well. Otherwise, developers would have adopted the Testing API a lot more.
One major drawback is that you need to write an extra API for your tests. It costs time and money, of course. And we all know that both resources are always limited. However, because the Testing API is part of your overall system, you need to think about how it fits into the architecture of your system.
Of course, one fair argument is that with a Testing API, we shift the refactoring issue. With the Testing API, we might not need to refactor our use-case tests, but we might need to refactor the code inside the API.
Because you have your use-case-driven tests, you might also write fewer unit tests. Writing more periodic tests is not necessarily bad because the combination of different tests makes our application more robust. Nevertheless, if you care about metrics like code coverage, those tests affect that. Your code is now covered indirectly through the Testing API.
As mentioned above, implementing a Testing API isn't easy. Especially in the short term creating the API costs time. It would help if you kept in mind that this extra effort can be challenging to handle. In the long run, though, refactorings will cost you less time due to the structural decoupling between the production code and the test code. You are still able to verify business rules but only through the Testing API.
No matter the effort, it is always worth thinking about ways to decouple the structure of your production code from the design of your test code. The Testing API helps you achieve this goal, and it gives you the possibility to keep more extensive refactoring efforts as low as possible. In the end, this saves you time and money.
What do you think about this concept? I'm curious to hear your opinion on this topic. In the next part, we look at how to implement this kind of API with .NET. So stay tuned!
A Testing API can help you decrease the structural coupling between your production code and your test code. In the long run, it will save you much time! A bold claim, of course, and it sounds very theoretical. To provide you with more depth than just a basic concept, I want to show you today how you can implement a Testing API with .NET.
If you want to bring your API to production fast, Azure Functions are a good choice for that. In this post, we look at how we can implement REST APIs with Azure Functions which are highly scalable and easily maintainable.
Azure DevOps is a great tool for tracking the progress of your work, version control, and CI/CD. But how can you bring it together with Scrum? Especially Backlog Refinement events? In this post, I want to show you the customization power of Azure DevOps to leverage its feature to improve your Backlog Refinement events.