I think you are mistaken. Mocking and DI frameworks are two unrelated concepts. There is nothing in Java that forces you to use a DI framework, e.g., Spring if you want to use mocks during testing.
In theory, I agree, but I don't think that holds terribly true in practice.
One of the ideas behind IoC frameworks (which build on top of DI) is that you could swap out implementation classes. For a great deal of software (and especially in cloud-hosted, SaaS style microservice architecture) the test stubs are the only other implementations that ever get injected.
Most code bases could ditch IoC if Java provided a language-level construct, even if that construct were only for the test harness.
Java has a mechanism, just pass alternate implemenations in constructors. If you must, a setter method. For most code you don't need to bring in the overhead of Spring, and @Autowired isn't really more convenient typing wise. Plus your unit tests become trivial, they're just POJOs with @Test annotations.
Spring is great when you need that dynamic control at runtime (especially when code dependencies are separated by modules) but you're just aping what good dynamic languages like Clojure or Common Lisp give you for free. But I can't complain too much, developing modern Java with its popular frameworks and with JRebel is getting closer to the Lisp experience every year, I'd rather have that than for Java to remain stagnate like in its 1.6/1.7 days.
Let's say I have a class called User and in it a method that says the current time. So User#say_current_time
which simply accesses the Date class (it takes no arguments).
Can you show me how you would mock the current time of that method in Java?
Without using a mock framework, assuming User#say_current_time isn't a private or static method then:
final Date testDate = someFixedDate;
User testUser = new User() {
@Override
Date say_current_time() {
return testDate;
}
};
If it is private and/or static, you can get around it without having to change the code, but if you own the code, you should just do that... Often the change will be as simple as replacing some method's raw usage of Date.now() with a local say_curent_time() method that uses it or some injected dependency just so you can mock Date.now() without hassle.
But your point further down that in Java you have to think about your code structure more to accommodate tests is valid. I think it's easy to drink the kool-aid and start believing that many code structuring styles that enable easier testing in Java are actually very often just better styles regardless of language, but you're not going to really see the point if you do nothing but Ruby/JS where you can get away with not doing such things for longer. Mostly it has to do with dynamic languages offering looser and later and dynamic binding than static languages (which also frequently makes them easier to refactor even if you don't have automated tools). One big exception is if your language supports multiple dispatch, a lot of super ugly Java-isms go away and you shouldn't emulate them. The book Working Effectively with Legacy Code is a good reference for what works well in Java and C++ (and similar situations in other languages), it's mostly about techniques for breaking dependencies.
I'll take clean contractual interfaces (aka actual principle of least surprise) over "I can globally change what time means with one line of code!" on large projects every time.
If you want to use DI, in java 8 you could inject a java.time.Clock instance in the constructor and provide a fixed instance at the required time in your test e.g.
Instant testNow = ...
User u = new User(Clock.fixed(testNow, ZoneOffset.UTC));
u.sayCurrentTime();
although it would be better design to have sayCurrentTime take a date parameter instead of depending on an external dependency.
In my experience the need to mock out individual methods like this is an indication that the code is badly structured in the first place. The time source is effectively a global variable so in this example you'd want to pass the time as a parameter to `sayCurrentTime` and avoid the need to mock anything in the first place. A lot of C#/java codebases do seem to make excessive use of mocks and DI in this way though.
OK. first I could be ignorant about Java since I haven't touched it in more than a decade. Which library is doing that? And also what is mock(User.java) returning - is it an actual User instance or a stub? I want a real User instance (nothing mocked in it) with just the one method mocked.
And again if this is possible I will admit ignorance and tip my hat at the Java guys.
It's Mockito [1], which has been a standard for a while. There are other libraries and they use different strategies to provide this kind of functionalities (dynamic proxies, bytecode weaving, annotation processing, etc...).
I think what you want is a "spy" (partial mock), not a full "mock", but yes, both are possible. You can partially mock classes, i.e., specific methods only. Syntax is almost the same, instead of mock(User.class) you write spy(User.class).