Hi all, I am currently working on some functions and when writing tests for these, I had problems sensibly testing things, as the singletons were preventing that. As I mentioned before … I consider the usage of singletons the probably worst design decision done in IoTDBs core. Even if it simplifies “composition”, it really makes everything else more complicated.
Knowing how deeply rooted in IoTDB the use of singletons is, I always thought this would be a never-ending story. But I just recently had an idea of how we could probably find a way to get the testability that we need without having to give up on singletons. Possibly this path could also provide a path to getting rid of singletons over time. As I was just working on DataNodeServerCommandLine I did an experiment with that, and it worked nicely. So, I searched for all singletons used in the component and defined private final member variables for each of them. In the no-args constructor I initialize these via the singletons, but I also add a second constructor, that allows passing in explicit versions. private final ConfigNodeInfo configNodeInfo; private final IClientManager<ConfigRegionId, ConfigNodeClient> configNodeClientManager; private final DataNode dataNode; /** Default constructor using the singletons for initializing the relationship. */ public DataNodeServerCommandLine() { configNodeInfo = ConfigNodeInfo.getInstance(); configNodeClientManager = ConfigNodeClientManager.getInstance(); dataNode = DataNode.getInstance(); } /** * Additional constructor allowing injection of custom instances (mainly for testing) * * @param configNodeInfo config node info * @param configNodeClientManager config node client manager * @param dataNode data node */ public DataNodeServerCommandLine( ConfigNodeInfo configNodeInfo, IClientManager<ConfigRegionId, ConfigNodeClient> configNodeClientManager, DataNode dataNode) { this.configNodeInfo = configNodeInfo; this.configNodeClientManager = configNodeClientManager; this.dataNode = dataNode; } With this was I now able to write real unit-tests for the component, without having to require writing an Integration-test which costs a lot more resources and which makes implementing unhappy-path tests really challenging. With this approach, I think we can really improve testability in IoTDB … considering a class test coverage of only 24% and a method coverage of just 19% in the data node, we really need this. What do you all think? Chris