Singletons and Testing

The utility of singletons for testing api integration

Afonso Araújo (Streeterxs)
3 min readSep 9, 2020
Photo by Ferenc Almasi on Unsplash

It’s a common knowledge that Singletons are not easy to test. They break some OOP rules, and when you use it, your code base become dependant of it. But recently in my works on a javascript backend I needed to test api integration with a OAuth2 authentication service. That kind of service needs a saved Client and User in your database, so you can authenticate before making request to other routes/resources. That is difficult to maintain data integrity between tests case. Because my Jest testing environment cleans a in memory mongoDB database after each testing case. So a unconcentrated or unexperienced developer could do a little mess on tests implementation.

So let’s start from the beginning…

My application has a GraphQL Schema that manages Users and Persons, implemented with it’s tests for each mutations and queries. So I begin a OAuth2 implementation with a permissions (admin, manager, common and visitor) feature. And forbidden any request made to /graphql route if the user isn’t a authenticated admin. Now I need to create client, create a admin user, authenticate it, add access token to request’s header before use my tests again.

Singletons…

was used to do that job for me. I created a singleton for Client and another for User. For the client, it returns only a Client object on it’s getClient method. If no Client is instantiated, a new Client is created and returned from that method. For the User Singleton I made a little more complex. To ease testing I store 4 user object in that Singleton, one for each permission (That way I can call getAdmin() to create a test case with a admin user). Each one has a reset() method, because each test cleans the database, invalidating any stored object by my singletons.

Client Singleton
Users Singleton

Tests Abstraction

I made it that way to abstract all that aforementioned logic and making easy to test with differents types of User. After do all implementations, my tests case files increased only two lines, and a couple of strings (for selecting user type). All my before integration logic for testings already was abstracted to a javascript’s closure module. That module received a new ‘reset’ function that execute all singletons reset method. And that are being executed inside before database clear function inside my afterEach() method.

Testing module. After each test case the database is cleaned and users are reseted
‘admin‘ string to select a user with admin permission

Conclusions

I love how much lexical is now to make my testing for each user type. But thinking on how much effort I made on that some could say that is not worth it, I still need to create testing case for each of create client and user. Gladly I needed to build it only one time for all my tests work with Oauth2 + permissions which isn’t simple to make it work. And if any other feature in the future is created, doing tests implementation will be simple as it is now.

Thank you for reading! :)

--

--