Skip to main content

Testing

2023

Golang Tutorial: Contract Testing with PACT

·2678 words·13 mins· loading · loading
My favorite part of software development is writing tests, whether they are unit tests or integration tests. I enjoy the process immensely. There’s a certain satisfaction in creating a test case that uncovers a function’s failure. It brings me joy to discover a bug during development, knowing that I’ve fixed it before anyone encounters it in a test environment or, worse, in production. Sometimes, I stay up late just to write more tests; it’s like a hobby. I even spent around 30 minutes on my wedding day writing unit tests for my personal project, but don’t tell my wife! The only thing that used to bother me was dealing with integration issues between multiple Microservices. How could I ensure that two Microservices, each with specific versions, wouldn’t face integration problems? How could I be certain that a new version of a Microservice didn’t break its API interface, rendering it unusable for others? This information was crucial to have before launching extensive scenarios in our end-to-end testing pipeline. Otherwise, we’d end up waiting for an hour just to receive feedback that we’d broken the JSON schema. Then, one day in the office, I heard a rumor that we were planning to use Contract Testing. I quickly checked the first article I found, and I was amazed. It was a breakthrough. Contract Testing # There are many excellent articles about Contract testing, but the one I like the most is from Pactflow. Contract testing ensures that two parties can communicate effectively by testing them in isolation to verify if both sides support the messages they exchange. One party, known as the Consumer, captures the communication with the other party, referred to as the Provider, and creates the Contract. This Contract serves as a specification for the expected requests from the Consumer and the responses from the Provider. Application code automatically generates Contracts, typically during the unit testing phase. Automatic creation ensures that each Contract accurately reflects the latest state of affairs. Contract testing After the Consumer publishes the Contract, the Provider can use it. In its code, likely within unit tests, the Provider conducts Contract verification and publishes the results. In both phases of Contract testing, we work solely on one side, without any actual interaction with the other party. Essentially, we are ensuring that both parties can communicate with each other within their separate pipelines. As a result, the entire process is asynchronous and independent. If either of these two phases fails, both the Consumer and Provider must collaborate to resolve integration issues. In some cases, the Consumer may need to adapt its integrational code, while in others, the Provider may need to adjust its API.

Golang Tutorial: Unit Testing with Mocking

·3513 words·17 mins· loading · loading
Unit testing has always been my thing, almost like a hobby. There was a time when I was obsessed with it, and I made sure that all my projects had at least 90% unit test coverage. You can probably imagine how much time it can take to make such a significant change in the codebase. However, the result was worth it because I rarely encountered bugs related to business logic. Most of the issues were related to integration problems with other services or databases. Adding new business rules was a breeze because there were already tests in place to cover all the cases from before. The key was to ensure that these tests remained successful in the end. Sometimes, I didn’t even need to check the entire running service; having the new and old unit tests pass was sufficient. Once, while working on a personal project, I had to write unit tests to cover numerous Go structs and functions—more than 100 in total. It consumed my entire weekend, and late on a Sunday night, before heading out on a business trip the next day, I set an alarm clock to wake me up. I had hardly slept that night; it was one of those restless nights when you dream but are also aware of yourself and your surroundings. My brain was active the entire time, and in my dreams, I kept writing unit tests for my alarm clock. To my surprise, each time I executed a unit test in my dream, the alarm rang. It continued ringing throughout the night. And yes, I almost forgot to mention, for two years, we had zero bugs in production. The application continued to fetch all the data and send all the emails every Monday. I don’t even remember my Gitlab password anymore. Unit Testing and Mocking (in general) # In Martin Fowler’s article, we can identify two types of unit tests: Sociable unit tests, where we test a unit while it relies on other objects in conjunction with it. For example, if we want to test the UserController, we would test it along with the UserRepository, which communicates with the database. Solitary unit tests, where we test a unit in complete isolation. In this scenario, we would test the UserController, which interacts with a controlled, mocked UserRepository. With mocking, we can specify how it behaves without involving a database.