Shall we avoid writing static methods in our java code for better testability?

java, static

Solution

Beware of overengineering.

In your specific example, you either do or don't have a mockability issue. Since you are asking this in general, I'll assume you don't have a specific issue at the moment.

The general argument is that `static` methods are simpler and therefore the preferred choice, whenever there is a choice. A would-be instance method must first prove itself of needing to be an instance method.

If this was my project, I would defer any makeovers into instance methods until such a moment where the need for that became clear and present.

Problem

I was prefer using static methods in my java code, since I think they are "functional""stateless" and has less side-effect. So there may be some helper classes and methods like this: ``` public class MyHelper { public static Set<String> array2set(String[] items) { ... } public static List<String> array2list(String[] items) { ...} public static String getContentOfUrl(String url) { // visit the url, and return the content of response } } public class MyApp { public void doSomething() { String[] myarray = new String[]{ "aa","bb"}; Set<String> set = MyHelper.array2set(myarray); String content = MyHelper.getContentOfUrl("http://google.com"); } } ``` But my friend says we should avoid defining such static utility methods, since we call them directly in our code, it will be hard to mock them or test them if they have external dependencies. He thinks the code should be: ``` public class ArrayHelper { public Set<String> array2set(String[] items) { ... } public List<String> array2list(String[] items) { ...} } public class UrlHelper { public String getContentOfUrl(String url) { // visit the url, and return the content of response } } public class MyApp { private final ArrayHelper arrayHelper; private final UrlHelper urlHelper; public MyApp(ArrayHelper arrayHelper, UrlHelper urlHelper) { this.arrayHelper = arrayHelper; this.urlHelper = urlHelper; } public void doSomething() { String[] myarray = new String[]{ "aa","bb"}; Set<String> set = arrayHelper.array2set(myarray); String content = urlHelper.getContentOfUrl("http://google.com"); } } ``` In this way, if we want to write unit tests for `MyApp`, we can just mock the `ArrayHelper` and `UrlHelper` and pass them to the constructor of `MyApp`. I agree totally about the `UrlHelper` part of his opinion, since the origin static code make `MyApp` untestable. But I have a little confused about the `ArrayHelper` part, since it doesn't depend on any external resources and the logic will be very simple. Shall we avoid using static methods at this case too? And when to use static methods? Or just avoid using it as much as possible? update: We are using "TDD" in our development, so the testability of a class often is the most important concern for us. And I just replace the word "functional" with "stateless" in the first sentence since the that's real what I meant.

Original source