Stop testing your (de)serializers
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.
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
@Test
fun `serialise a customer`() {
val serializer = UserSerializer()
val result = serializer.toJson(User("john", "wilson"))
JSONAssert.assertEquals(
"""{ "name": "john", "lastName": "wilson" }""", result, true
)
}Why is it wrong? It puts too much emphasis on implementation details making the tests more fragile. We shouldn’t be able to instantiate UserSerializer from the tests. (De)serializers are adapter details; they should be able to change freely without impacting anything else other than their own adapter. The only way to guarantee it is by making them private within their adapter. This helps to keep JSON concerns where they belong: the outer layers of your architecture and never your domain. It also helps achieve vertical decoupling of use cases.
You might argue that a serializer could be shared across multiple web handlers (e.g. a customer JSON that is used in its detail and its listing) but that just shows an abuse of the DRY principle. The serializers may look the same, but that is only a coincidence since they will probably evolve in different directions. Even if they were shared, that wouldn't free you from properly testing the multiple web handlers separately.
(De)serializers are just a glorified kind of toString and therefore not supposed to have any business logic, only transformation code. Testing them directly is just testing data conversion (object ⭤ JSON). If you’re using some JSON library or the runtime, it almost feels like you’re testing it, which hopefully is thoroughly tested by its developers. Therefore, it doesn’t pay off in terms of improving the test safety net.
✅ The proper way to test (de)serializers
Let’s now consider a way to test (de)serializers in the context of their owner adapter. Being an indirect way, the test coverage remains the same. The difference is that we’ll test an actual component, not some implementation detail. We don’t care how the (de)serialization happens as long as it’s done. Let’s go over an example of testing a web handler to get a list of users in JSON.






