Does your backlog contain technical stories like migrations, upgrades, refactors, and other chores? I’ll try to convince you not to.

Image for post
Image for post
A board in Pivotal Tracker

I assume you, developer or not, care about your backlog. Backlogs, like codebases, need and deserve care from everyone in the team. I’m a fan of continuous codebase improvement through constant refactoring. I love coding and I care a lot about all the codebases I work with. I understand migrations and upgrades need to happen, so why do I propose we stop creating technical stories? There’s a lot of harm in doing so. Let’s see why.

A tech-driven approach

What are you paid for? I often hear “to write code”. I don’t agree with that at all since I believe we’re paid to…

Do you feel safe regarding your testing strategy? Do you follow testing patterns consistently? Are you tired of debating what is a unit versus an integration test? I’ll propose a way to visualize your testing strategy so you can tackle those questions.

Image for post
Image for post

The testing strategy is how you approach the automated testing of your software. Given its importance, it should be taken seriously. I’ll propose a visual way to represent it, as visual representations promote discussion, a shared understanding, and support decision making.

In a world full of technicians and politicians all having different levels of understanding, a graphic representation was often the only way to make a point; a single plummeting graphic usually aroused ten times the reaction inspired by volumes of spreadsheets. Digital Fortress

Before starting…

… we need to define some terminology (inspired in xUnit Test Patterns). I avoid the terms…

I heard about contract testing as an alternative to integration testing and finally decided to learn its concepts and try it out using

Image for post
Image for post

How do you ensure multiple apps and services of the same system play well together?
You could run end-to-end testing but it’s nearly impossible to test all the combinations. Also, the effective pinpointing of problems would be very low.
You could also test in isolation, on a per-app basis by simulating the other services' replies, but since they can evolve independently, the safety net is low as each set of tests may pass although the integration is broken.
Finally, integration testing is the typical solution because tests are run against the depended-on services. …

There are multiple techniques, and the ones you use depend on your testing strategy.

The techniques to test the data layer can be direct, like testing against an in-memory database (e.g. H2) or against a real database (e.g. using Docker) or indirect, like launching the backend application or testing as the end-user (UI tests). Let’s go over the direct options. The presented techniques can be applied regardless of the database technology (e.g. PostgreSQL, Redis, MongoDB).

📝 When deciding the techniques you’ll use, bear in mind the testing automation goals and where it fits in your automated testing strategy.

Testing against an in-memory database

In order to unit test the data layer, we need to properly isolate it. Let’s imagine…

One of the goals of automated testing is “testing as a safety net” but that doesn’t mean that you should unit test everything. (De)serialization is an example of something that you should not test directly.

According to the hexagonal architecture, an adapter belongs to the outer layer of your app; it’s the glue between a component and the outside world, whether a database, a gateway for a REST API, your own REST API, etc. Adapters should only deal with parsing, (de)serialization, routing, error handling, and similar; they should never contain any kind of business logic.

Image for post
Image for post
Source: Hexagonal Architecture with Java and Spring

The need to store and transmit data requires some kind of string representation which is given by serializers (object → string). Deserializers do the opposite (string → object). JSON is just a possible string representation but there are others.

🛑 The wrong way to test (de)serializers


There are a few things we keep hearing and doing but we seldom question, like “code comments are good” or “magic numbers are bad”. Let’s address the latter.

Image for post
Image for post

Creating constants can be a symptom of some underlying anti-patterns. But aren’t magic numbers (or strings, etc.) a bad practice? Well… don’t follow rules just because you always did it. Let’s address the typical arguments (we’ll use Kotlin in the snippets).

“But I can use them in the tests!”

This is the worst reason to create constants. Tests should know nothing about the implementation other than its public APIs. Initially, a certain constant was local/private but you promoted it to global for the sake of testing. This was a bad idea because now the tests are coupled with the implementation. Tests should be seen as clients of the…

Testing is more than creating a safety net.

In an agile mindset, the team is responsible for the delivered software, which includes quality assurance (QA). In this scenario, QA is a role that is adopted by the team as a whole — developers should be writing automated tests. Manual testing does not scale as it’s hard to reproduce, tedious, error-prone, and not compatible with continuous delivery. However, if there are QA specialized people, they should be doing other types of work (e.g. exploratory testing), but I’ll leave that for another article.

Automating everything — from build to tests, deployment and infrastructure — is your only way forward.

In Kotlin/Java, how would you test that your app is properly consuming an external REST API? We’ll use Javalin to do it.

Image for post
Image for post
How do you unit test a gateway in your app?

My proposal is to use Javalin (a lightweight webserver) as the test double, thereby replacing the external API (the DOC: dependent-on component). We’ll launch Javalin acting as the real API but running in localhost so that the gateway (the SUT) can’t tell the difference. We’ll confirm the validity by asserting the calls made to the test double.

How do you ensure that two given components speak the same language? Do you have invalid values floating around? Would you represent dates as strings internally? Then why do you represent your domain concepts as strings and integers? It makes no sense.

Image for post
Image for post

📝 Java enums are a native example of value objects but they’re not adequate for an arbitrary amount of values. Typical value objects are email, password, locale, telephone number, money, IP address, URL, entity identifier, rating, file path, point, color, date, date range, distance.

Value objects are one of the building blocks of domain-driven design. Let’s explore their main characteristics (using Kotlin).

Carry a value

The value object is a container and carrier of an arbitrary value:

The literal value is kept inside the value object 🚀

Usually, a value object holds a single value, but it can hold more. For example, an…

I see some people struggling to write a unit test. I remember that pain some time ago. This is the article I wish I have read back then. I’ll present a systematic approach to write unit tests.

Image for post
Image for post

Test-Driven Development — TDD puts the test in the spotlight: it’s how you drive your implementation. TDD forces you to separate the “what” (test) from the “how” (implementation) so you can focus at one at a time. That’s why it can also be seen as Test Driven-Design and why the test is also known as spec (i.e. specification).

When learning TDD, you’ll hear a lot about the TDD cycle. What is that? It’s just a fancy name for the typical TDD state transitions between test/design → implement → refactor:

Luís Soares

full-stack developer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store