I'm trying to implement unit testing for aproject, it uses a legacy "utility" project that is littered with static methods and many of the classes are final or their methods are final. I'm not able to update the legacy project at all.
JMock and EasyMock both choke on final methods, and I don't see a nice way to test the static calls. What techniques are there to test these?
If you're able to refactor your code, you can wrap your calls to the final/static methods in simple instance methods, for example:
protected Foo doBar(String name) {
return Utility.doBar(name);
}
This allows you to override your wrapper method in the unit test to return a mock instance of Foo.
Alternatively you can use Powermock, which extends Easymock (and Mockito) to allow mocking of final and static methods:
PowerMock is a framework that extend other mock libraries such as EasyMock with more powerful capabilities. PowerMock uses a custom classloader and bytecode manipulation to enable mocking of static methods, constructors, final classes and methods, private methods, removal of static initializers and more.
Here's an example test mocking a static final method, the example shows how to mock some other types too:
#Test
public void testMockStaticFinal() throws Exception {
mockStatic(StaticService.class);
String expected = "Hello altered World";
expect(StaticService.sayFinal("hello")).andReturn("Hello altered World");
replay(StaticService.class);
String actual = StaticService.sayFinal("hello");
verify(StaticService.class);
assertEquals("Expected and actual did not match", expected, actual);
// Singleton still be mocked by now.
try {
StaticService.sayFinal("world");
fail("Should throw AssertionError!");
} catch (AssertionError e) {
assertEquals("\n Unexpected method call sayFinal(\"world\"):",
e.getMessage());
}
}
How about a level of indirection / Dependency Injection?
Since the legacy utility project is your dependency, create an interface to separate it out from your code. Now your real/production implementation of this interface delegates to the legacy utility methods.
public LegacyActions : ILegacyActions
{
public void SomeMethod() { // delegates to final/static legacy utility method }
}
For your tests, you can create a mock of this interface and avoid interacting with the legacy utility thingie.
JMockit allows you to mock static methods and final classes. I assume it uses some classloadin-fu, although I haven't really looked into it.
JMockit Expectations API allows
expectations to be set on any kind of
method invocation (on interfaces,
abstract classes, concrete final or
non final classes, and on static
methods), as well as on class
instantiation through any
constructors.
As already pointed out, JMockit can be used.
An example:
#Test
public void mockStaticAndFinalMethods(#Mocked LegacyService mock) {
new Expectations() {{
LegacyService.staticMethod("hello"); result = "Hello altered World";
}};
String actual = LegacyService.staticMethod("hello");
new LegacyService().finalMethod(123, "test");
assertEquals("Hello altered World", actual);
new Verifications() {{
mock.finalMethod(123, "test"); // verify this call occurred at least once
}};
}
If your non-refactorable method uses something like JNDI to connect to another service, I'd consider starting a JDNI service and populating it with stubs which you control. It's a pain but relatively straightforward. It may mean setting up a database or JMS listener or whatever but there should be a lightweight java implementation you can drop into the tests.
JMock together with JDave can mock final methods and classes, if you need to. Here
are instructions. That being said I would treat this legacy code (as others have suggested already) as an external dependency and build interfaces and mock those. It is another layer of indirection, but since you can't change that legacy code, it seems to be a reasonable one.
Related
Java Question: I am working on a class (call it ProcessorA that only extends Object. It is also stateless). It will reside in a Spring Service on a Web Server. The class declares several public methods as the class' API.
I want to test this class with a simple JUnit test. I need to test some functionality that is a few method calls deep inside of 1 public method. However, between the API Method and the method to test there are several classes would be loaded at runtime by Spring in the Web Server.
I can completely by-pass this by declaring the method to be tested as a 'default' method and calling it directly from an instance (of ProcessorA) from the JUnit test.
I have been told that this is NOT a best practice.
However, I am at a loss as to exactly what is gained by further restricting access to the method to be tested.
So, what is it that can be gained by declaring a method as private over default (which is more restrictive than "protected" (which by inclusion is also verboten). \
public class ProcessorA {
public methodA(String input) throws ValidationException {
doSomeValidationStuff(input);
doStuffToTest(input);
}
private doSomeValidationStuff(String input) throws ValidationException {
//Libraries that are not loaded at execution and not available for the JUnit test
}
doStuffToTest(String input) {
//Code to be tested}
}
}
class MyJunitTest {
#Test
void doStuffToTestTest() {
ProcessorA processorA = new ProcessorA();
String testData = "test data String";
assertNotNull( processorA.doStuffToTest(testDate));
}
}
The answer that I am looking for isn't for how to get around this constraint, but what is gained by blindly following a blanket directive that has (seemingly) no payoff.
Default scope in Java is a package-private scope which means that all classes from the same package can use this method. If you restrict it to private, only methods from the same class can do it. This is what we gain. It is your decision, do you need to expose this method to other classes or it is enough to just keep it private but don't expose something only for testing purposes.
I am facing problem while testing method using Mockito.
please check testMethodToBeTested() method of JunitTestCaseClass, which has to handle static method call of thirdparty class.
class ClasssToBeTested{
public String methodToBeTested() {
String result = ThirdPartyUtilClass.methodToBeCall();
return result;
}
}
class ThirdPartyUtilClass{
public static String methodToBeCall(){
return "OK";
}
}
// JunitTestCase which will test method "methodToBeTested()" of ClasssToBeTested class
class JunitTestCaseClass{
#InjectMocks
private ClasssToBeTested classsToBeTested;
#Test
public void testMethodToBeTested() {
//How to handle ThirdPartyUtilClass.methodToBeCall(); statement in unit testing
String result = classsToBeTested.methodToBeTested();
Assert.assertNotNull(result);
}
}
Please help & Thanks in Advance.
I think this is your answer why it is not working:
https://github.com/mockito/mockito/wiki/FAQ
What are the limitations of Mockito
Mockito 2.x specific limitations
Requires Java 6+
Cannot mock static methods
Cannot mock constructors
Cannot mock equals(), hashCode().
Firstly, you should not mock those methods. Secondly, Mockito defines and depends upon a specific implementation of these methods. Redefining them might break Mockito.
Mocking is only possible on VMs that are supported by Objenesis. Don't worry, most VMs should work just fine.
Spying on real methods where real implementation references outer Class via OuterClass.this is impossible. Don't worry, this is extremely rare case.
If you really want to mock static methods then PowerMock is your solution.
https://github.com/powermock/powermock/wiki/mockito
I want to mock my grpc client to ensure that it is resilient to failure by throwing an new StatusRuntimeException(Status.UNAVAILABLE) (This is the exception that is thrown when java.net.ConnectException: Connection refused is thrown to the grpc client). However, the generated class is final, so mock will not work.
How do I get BlahServiceBlockingStub to throw new StatusRuntimeException(Status.UNAVAILABLE) without having to refactor my code to create a wrapper class around BlahServiceBlockingStub?
This is what I have tried (where BlahServiceBlockingStub was generated by grpc):
#Test
public void test() {
BlahServiceBlockingStub blahServiceBlockingStub = mock(BlahServiceBlockingStub.class);
when(blahServiceBlockingStub.blah(any())).thenThrow(new StatusRuntimeException(Status.UNAVAILABLE));
blahServiceBlockingStub.blah(null);
}
Unfortunately I get the below exception as expected:
org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class BlahServiceGrpc$BlahServiceBlockingStub
Mockito cannot mock/spy following:
- final classes
- anonymous classes
- primitive types
at MyTestClass.test(MyTestClass.java:655)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
.
.
.
Because I tried mocking the final class generated by grpc:
public static final class BlahServiceBlockingStub extends io.grpc.stub.AbstractStub<BlahServiceBlockingStub> {
private BlahServiceBlockingStub(io.grpc.Channel channel) {
super(channel);
}
Do not mock the client stub, or any other final class/method. The gRPC team may go out of their way to break your usage of such mocks, as they are extremely brittle and can produce "impossible" results.
Mock the service, not the client stub. When combined with the in-process transport it produces fast, reliable tests. This is the same approach as demonstrated in the grpc-java hello world example.
#Rule
public final GrpcCleanupRule grpcCleanup = new GrpcCleanupRule();
#Test
public void test() {
// This can be a mock, but is easier here as a fake implementation
BlahServiceImplBase serviceImpl = new BlahServiceImplBase() {
#Override public void blah(Request req, StreamObserver<Response> resp) {
resp.onError(new StatusRuntimeException(Status.UNAVAILABLE));
}
};
// Note that the channel and server can be created in any order
grpcCleanup.register(InProcessServerBuilder.forName("mytest")
.directExecutor().addService(serviceImpl).build().start());
ManagedChannel chan = grpcCleanup.register(
InProcessChannelBuilder.forName("mytest").directExecutor().build();
BlahServiceBlockingStub blahServiceBlockingStub
= BlahServiceGrpc.newBlockingStub();
blahServiceBlockingStub.blah(null);
}
When doing multiple tests, you can hoist the server, channel, and stub creation into fields or #Before, out of the individual tests. When doing that it can be convenient to use MutableHandlerRegistry as a fallbackHandlerRegistry() on the server. That allows you to register services after the server is started. See the route guide example for a fuller example of that approach.
You have a few options:
NOT RECOMMENDED: Use Mockito v2 to mock final classes and methods.
NOT RECOMMENDED: Use powermock to mocks final classes and methods.
Recommended: (as already mentioned by Eric in his answer) Use the gRPC Java test framework like GrpcCleanupRule and InProcessServerBuilder. See HelloWorldClientTest for an example.
Recommended: Do over-the-wire gRPC API mocking/simulation. Use a third-party tool that will create over-the-wire API mocks/simulators for your API. For example, Traffic Parrot.
Note why mocking final, in this case, might be a bad idea:
Mocking final classes or methods might be a bad idea, depending on the case. The devil is in the details. In your situation, you are creating a mock of the generated code, so you are assuming how that generated code will behave in the future. gRPC and Protobuf are still rapidly evolving, so it might be risky to make those assumptions, as they might change and you won't notice because you do not check your mocks against the generated code. Hence, it's not a good idea to mock the generated code unless you really have to.
How to mock final classes/methods with mockito:
add dependency Mockito Inline
create file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
with one line: mock-maker-inline
And now you can mock final methods and classes.
Mockito docs about mocking
I ended up with an ugly workaround.
I created a new method and a spy() on the class that has a reference to BlahServiceBlockingStub.
The resulting code ended up looking like:
#Test
public void test() {
MyClass myClass = spy(myClass);
doThrow(new StatusRuntimeException(Status.UNAVAILABLE)).when(myClass).newMethod(any());
// changed to call myClass.newMethod() instead of blahServiceBlockingStub.blah
myClass.myExistingMethod();
}
I was trying to write unit test using jmocks and junit. (My Project uses core java- no frameworks-) I could not write unit test for some of my classes, by mocking external dependencies, when dependencies were initialized in a a no arg-constructor.
As i cannot provide the actual code, trying to explain the scenario by an example
public interface Apple {
String variety();
}
Implementation.
public class MalgovaApple implements Apple {
#Override
public String variety() {
return "Malgova";
}
}
Class to be tested
public class VarietyChecker {
private Apple apple;
VarietyChecker(){
this.apple = new MalgovaApple();
// instead of new, a factory method is used in actual application
}
public String printAppleVariety(){
String variety = apple.variety();
if(variety.length() < 3){
System.out.println("Donot use Code names- Use complete names");
return "bad";
}
return "good";
}
}
Junit test using jmock
public class VarietyCheckerUnitTest{
Mockery context = new JUnit4Mockery();
#Before
public void setUp() throws Exception {
}
#After
public void tearDown() throws Exception {
}
#Test
public void test_VarietyChecker() throws Exception{
final Apple mockapple = context.mock(Apple.class);
VarietyChecker printer = new VarietyChecker();
context.checking(new Expectations(){{
oneOf(mockapple).variety();will(returnValue("as"));
}});
String varietyNameValid = printer.printAppleVariety();
assertEquals("bad",varietyNameValid);
} }
This test fails - Mocking does not work the values "as" is not injected, the test class executes with MalgovaApple ...
Now if we add below constructor to VarietyChecker and use it test case - it gives expected output...
public VarietyChecker(Apple apple) {
super();
this.apple = apple;
}
and in unit test create test class object like
VarietyChecker printer = new VarietyChecker(mockapple);
Exposing a new constructor just for the purpose of testing is not a good idea. After all it is said that you should not alter the code for testing alone, more than that, i am afraid we have already written "some"(amount) code...
Am i missing something in junit or jmock that can make mocking work even incase of no-arg constructors. Or is this a limitation of simple junit and jmocks and should i migrate to something powerful like Jmockit /PowerMock
You should consider two choices.
Use a constructor parameter as you describe.
In this case, you're not "exposing a new constructor just for the purpose of testing". You're making your class more flexible by allowing callers to use a different factory implementation.
Don't mock it.
In this case, you are declaring that it never makes sense to use a different factory. Sometimes this is okay. At that point, the question changes, though. Instead of, "How do I mock this?" your question is now, "What am I gaining from writing this test?" You might not be gaining much of anything, and it might not make much sense to write the test at all.
If you don't mock it and decide a unit test is still worth it, then you should be asserting on other aspects of the code. Either an end state or some output. In this case, the factory call becomes an implementation detail that's not appropriate for mocking.
It's important not to fall for a "unit test everything" mentality. That is a recipe for Test-induced Design Damage. Evaluate your tests on a case by case basis, deciding whether they're providing you any real value or not. Not writing a unit test is a valid option and is even appropriate at times, even if it's option you try very hard to avoid.
Only you can make a determination which one makes the most sense in this case. From the the fact that this is a factory object we're talking about, I'd probably lean toward the former.
I have class with a forwarding method foo:
void foo( Concrete c, String s ) { c.bar( s ); }
I wish to test whether foo does, in fact, forward. Unfortunately for me, Concrete is a class in a third-party library, and is a concrete type, not an interface. Thus I must use ClassImposteriser in JMock to mock Concrete, so in my test case, I do this:
#Test
public final void testFoo() {
Mockery context = new JUnit4Mockery() {{
setImposteriser(ClassImposteriser.INSTANCE);
}};
final Concrete c = context.mock(Concrete.class);
final String s = "xxx" ;
// expectations
context.checking(new Expectations() {{
oneOf (c).bar(s); // exception gets thrown from here
}});
new ClassUnderTest.foo( c, s );
context.assertIsSatisfied();
}
Unfortunately, Concrete.bar in turn calls a method that throws. That method is final, so I can't override it. Further, even if I comment out the line new ClassUnderTest.foo( c, s );, the exception is thrown when JMock sets up exceptions, not when foo is called.
So how can I test that method ClassUnderTest.foo does forward to Concrete.bar?
Edit:
Yes, bar is final.
My solution, which is not a general one, was to use a "Tester" class in the third-party library to correctly set up Concrete.
It's not clear from the question text if Concrete.bar() is final or if Concrete.somethingElse() is final and called from Concrete.bar().
If Concrete.bar() is not final, create a hand-written stub for Concrete like this:
public class ConcreteStub extends Concrete
{
public int numCallsToBar = 0;
#Override
public void bar(String s) { numCallsToBar++; }
}
and in your test code:
ConcreteStub c = new ConcreteStub();
foo(c,"abc");
assertEquals(1,c.numCallsToBar);
If Concrete.bar() is final, it is more complicated and the answer depends on the complexity of Concrete and your project's use of the Concrete class. If your use of Concrete is simple enough, I would consider wrapping Concrete in an interface (Adapter Pattern) that you can then mock out easier.
Benefits to the Adapter Pattern solution: Possibly clarify behavior by naming interface after your project's use of Concrete. Easier to test.
Drawbacks to the Adapter Pattern solution: Introduces more classes with possibly little benefit to production code. I don't know what Concrete does and it may not be practical to wrap Concrete in an interface.
See http://www.jmock.org/mocking-classes.html for info about mocking classes and how to bypass final limitations.
If a method is final then we can't do much about it. If this is a third-party library, then we would consider wrapping it in a veneer layer and mocking that, then doing integration tests to test against the library. There are other frameworks that will mock locked-down code, but we don't support it because we don't think it's a great idea.
Use a more capable mocking tool, such as JMockit. Your test could then be written as:
#Test
public void testFoo(final Concrete c)
{
final String s = "xxx";
new Expectations() {{
c.bar(s);
}};
new ClassUnderTest().foo(c, s);
}
For JMockit, it makes no difference if Concrete is an interface, a final class, an abstract class, or whatever. Also, there is no need to use #RunWith, extend a base test class, or call any method like assertIsSatisfied(); it's all done automatically, in a transparent way.