How make code that uses global dynamic properties unit testable?

373 views Asked by At

A lot of code needs to use some global flag or properties to control the flow of the application. It is necessary for a lot of scenarios to maintain a Dynamic Cache which will have a flag to lock/unlock a particular piece of (new)code.

For all such scenarios I usually write this way:

''' 
void someMethod(Data data){
  if(DynamicProperty.getValue("OK"))
    // Do Something

}

DynamicPropery is a Singleton which periodically refreshes the cache from the DB.
The problem with this is Unit testing is little tricky, so far I've used Jmockit to get around that - and it works fine.
But I was wondering if there can be a better way to write a method like that that can be easier for Unit testing.

3

There are 3 answers

4
Maciej Kowalski On BEST ANSWER

You can isolate all the property retrieval in some sort of PropertyResolverBean and then inject that in your SUT's and replace the static calls:

private PropertyResolverBean injectedPropertyResolverBean;

void someMethod(Data data){
  if(injectedPropertyResolverBean.getValue("OK"))
    // Do Something

}

Then you can use the basic features of Mockito for example in order to mock that bean and pre-configure your tests the way you want.

You end up with a more maintainable, readable and testable code at the end that follows the SRP rule.

4
davidxxx On

In a general way, hard-coded global constants should be avoided as much as possible. As you need to mock/switch a dependency, defining its methods as static makes it hard to accomplish since it strongly couples the client of the class to the statically class prefixed to.
Of course you can need to maintain a global state in the application but nothing prevents you from defining it as an object that you can inject as a dependency in the class they need it :

private DynamicProperty dynamicProperty;

public MyClass(DynamicProperty dynamicProperty){
   this.dynamicProperty = dynamicProperty;           
}

void someMethod(Data data){
  if(dynamicProperty.getValue("OK"))
    // Do Something
}

This is fairly straight with dependency injection but you can do it yourself with a plain constructor or setter invocation.
Of course you should change the static methods to instance methods to allow a natural way of mocking the invocations.

2
Andrei Dragotoniu On

the easiest way would be to extract the value before-hand and pass it to the method when needed.

void someMethod(Data data,SomeProperty dynamicProperty){
  if( dynamicProperty whatever)
    // Do Something
}

then your calling code becomes:

SomeProperty dynamicProperty = DynamicProperty.getValue("OK");    
someMethod(data, dynamicProperty);

this way you don't really change much, you get the dynamic property just when you need to, so you don't need to worry about that part and now you can easily test your method.

This is called functional coding basically, you remove the dependency and only pass data to a method which means the method now becomes free of dependencies and can be easily tested by injecting whatever values you want.

If you have more of these values hanging around, I would then create a separate class and group them all in one place, create an interface from it, pass that into the class constructor and then work with it that way. I probably wouldn't do this just for one value though, unless it really simplifies your code.