Re: testing a dependency on a static function.
Belebele wrote:
Basically, you can't, which is the whole problem and the point behind
"don't use static methods like that."
So, does that mean that the proper way to have testable code for this
example is to create an interface, create a concrete class that
implements that interface (perhaps the only one in the code base), and
then somehow provide the method under test with an instance of the
concrete class?
I'm not sure about the proper/only way, but yes that's what I assume.
Although there would always be at least two instances of said interface:
the runtime one and the test one. There could certainly be more than
one type of test instance too... testing tends to be a big deal.
If so, honestly, that sounds excessive to me: creating the interface
for that unique concrete class, and then having perhaps only a single
instance of the latter. That unique instance would have to be passed
(presumably as an argument to the constructor) to every object that
depends on it.
I haven't actually tried to do this in a large project yet, but I think
one way around this issue of passing around a lot of small interface
objects is to make one single large context object. All small
interfaces objects go into that one context object. The context object
gets passed into any init routines as needed. Then it depends on
whether you have an application context or a test contex what the object
actually contains.
In that light, I find it unfortunate that there is no tool support to
test a design in which this singleton-like abstraction does not have
to be modeled with an object.
I think you're looking for more of a framework rather than a tool. A
lot of frameworks provide for some classes to be initialized from a
config file, rather than hard-coded. Both java.util.logging and JEE
containers allow you to do this, for example.
I guess if you combine the above two paragraphs, you could do something
like this:
public class Main {
static Context context;
public static void main( String ... args ) {
// .. read config from file into properties...
context = new Context( properties );
// rest of program here
}
}
And then use (or pass around) Main.context. You could also set this
externally for testing, but it also strikes me as very sloppy and
something I would want to avoid. Once you decompose a program into
smaller modules this might be ok for the smaller modules.
I guess I also see as Java language flaw the fact that it forces all
constructs to be fit into the object paradigm (although I would not
want to get too bogged down in a discussion of that topic).
I'm disappointed that there wasn't more discussion here. I don't regard
myself as an expert by any means, but I think that almost any language
will have problems with similar constructs. C++ and C# at least are
fundamentally like Java, and C is similar enough that hard coding things
is also bad. Passing things in as parameters is almost always the right
way to go, regardless of language.