mobile menu icon

Example of role tests in JavaScript with Jest

Published by Manuel Rivero on 04/08/2022

Learning, Contract testing, Role testing, Object-Oriented Design, Polymorphic testing, Integration tests, Design Patterns


In this post we’ll show our last example applying the concept of role tests, this time in JavaScript using Jest. Have a look at our previous posts on this topic.

This example comes from a deliberate practice session we did recently with some developers from Audiense with whom we’re doing Codesai’s Practice Program in JavaScript twice a month.

Similar to what we did in our previous example of role tests in Java, we wrote the following tests to develop two different implementations of the TransactionsRepository port while solving the Bank Kata: the InMemoryTransactionsRepository and the NodePersistTransactionRepository.

These are their tests, respectively:

As what happened in our previous post, both tests contain the same test cases since both tests document and protect the contract of the same role, TransactionsRepository, which InMemoryTransactionsRepository and NodePersistTransactionRepository implement.

Again we’ll use the concept of role tests to remove that duplication, and make the contract of the role we are implementing more explicit.

Although Jest does not have something equivalent or similar to the RSpec’s shared examples functionality we used in our previous example in Ruby, we can get a very similar result by composing functions.

First, we wrote the behavesLikeATransactionRepository function. This function contains all the test cases that document the role and protect its contract, and receives as a parameter a testContext object containing methods for all the operations that will vary in the different implementations of this integration test.

Notice that in the case of Jest we are using composition, whereas we used inheritance in the case of Junit.

Then, we called the behavesLikeATransactionRepository function from the previous tests and implemented a particular version of the methods of the testContext object for each test.

This is the new code of InMemoryTransactionsRepositoryTest:

And this is the new code of NodePersistTransactionRepository after the refactoring:

This new version of the tests not only reduces duplication, but also makes explicit and protects the behaviour of the TransactionsRepository role. It also makes less error prone the process of adding a new implementation of TransactionsRepository because just by using the behavesLikeATransactionRepository function, you’d get a checklist of the behaviour you need to implement in order to ensure substitutability, i.e., to ensure the Liskov Substitution Principle is not violated.

These role tests using composition are also more readable than the Junit ones, in my opinion at least :)

Acknowledgements.

I’d like to thank Audiense’s deliberate practice group for working with us on this kata, and my colleague Rubén Díaz for co-facilitating the practice sessions with me.

Thanks to my Codesai colleagues for reading the initial drafts and giving me feedback, and to Elina Sazonova for the picture.

References.

Photo from Elina Sazonova in Pexels

Volver a posts