2

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.

Saum
  • 35
  • 1
  • 8

3 Answers3

3

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.

Maciej Kowalski
  • 25,605
  • 12
  • 54
  • 63
  • Yes, that is something that will work, just need to ensure that `PropertyResolverBean` is among the first classes to be instantiated. The other risk with this is .. somewhere down the line, there'll be a new developer who will forget about it and just do a `new PropertyResolverBean()` – Saum Jun 08 '19 at 11:03
  • Then he will have problem testing his solution and come to you? And you will tell him the correct one? Peer reviews + mandatory unit testing and your problem is literally gone – Maciej Kowalski Jun 08 '19 at 11:24
  • cant argue there .. it is mostly an process problem at that point. – Saum Jun 08 '19 at 11:30
  • Enforcing UT's is hard as very little devs know how to write them clear, efficient and maintainable. But good luck its worth trying ;) – Maciej Kowalski Jun 08 '19 at 11:38
2

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.

davidxxx
  • 125,838
  • 23
  • 214
  • 215
  • Yes, that seems to be the only and probably the best way that I can find. There just the risk of a new developer messing that up by creating a new instance, I've seen this happen a few times, which is why I guess I see these as Singleton's in the 1st place. – Saum Jun 08 '19 at 11:11
  • For existing implementations where `DynamicProperty` is a singleton, other than testabilty - what will be the other arguments towards making this a normal class with non-static methods. – Saum Jun 08 '19 at 11:26
  • "There just the risk of a new developer messing that up by creating a new instance." It is indeed possible if the developer is used to work on a project where dependency injection is not the rule. In this case, if a refactoring is performing, adding some javadoc on the constructor could make sense. – davidxxx Jun 08 '19 at 12:38
  • "what will be the other arguments towards making this a normal class with non-static methods?". To be able to switch to another implementation without changing the API from the client side, what the OOP allows and that static methods don't. For example, suppose at a time you need to have two distinct implementations of `DynamicProperty` for any reason. You should break the client code to do this change with static methods but you don't have this issue with instance methods (not final of course) or more generally with interfaces. – davidxxx Jun 08 '19 at 12:44
0

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.

Andrei Dragotoniu
  • 6,155
  • 3
  • 18
  • 32
  • This I think will just move the problem up the chain, who ever is calling the `someMethod()` now will have to read that property - so that method becomes difficult to test – Saum Jun 09 '19 at 10:18
  • you're missing the point, the point is to make testing easy, you inject a value and don't have to worry where you get it from. the reading of the value happens outside of the method you want to test. this is how you test functionality. if later you want to make sure your whole system works then you start writing integration tests and e2e tests. Unit testing is about testing small bits of code in isolation. – Andrei Dragotoniu Jun 09 '19 at 10:19