Testing a concrete third-party class with JMock - java

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.

Related

How to write unit test by mocking, when you have zero arg:constructors

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.

Use methods declared in implementation that are not defined in interface

I have a class defined by an interface
public interface Test {
void testMethod();
}
Test test = new TestImpl();
public class TestImpl implements Test {
#Override
public void testMethod() {
//Nothing to do here
}
public void anotherMethod() {
//I am adding this method in the implementation only.
}
}
How can I call anotherMethod?
test.anotherMethod(); //Does not work.
I want to be able to define a few methods in the implementation only because in my production code, the Test interface covers a pretty broad spectrum of classes and is implemented by multiple classes. I use methods defined in the implementation to set dependencies that aren't covered by the DI framework in my unit testing so the methods change from implementation to implementation.
The problem is with the following line:
Test test = new TestImpl();
This tells the compiler to forget that the new object is a TestImpl and treat it as a plain old Test. As you know, Test does not have anotherMethod().
What you did is called "upcasting" (casting an object to a more general type). As another poster has said, you can fix your problem by not upcasting:
TestImpl test = new TestImpl();
If you're sure that a Test object is really a TestImpl, you can downcast it (tell the compiler it is a more specific type):
Test test = new TestImpl();
:
((TestImpl) test).anotherMethod();
This is generally a bad idea, however, since it can cause ClassCastException. Work with the compiler, not against it.
use
TestImpl test = new TestImpl();
then
test.anotherMethod();//It will work now
I think through your Interface reference it is impossible to call any method which is not defined in that interface.
If you want to avoid casting directly to your implementation class, I would create another interface:
public interface SpecificTest extends Test {
void anotherMethod();
}
And then have your TestImpl implement that interface (which means you can declare it as either Test or SpecificTest ):
SpecificTest test = new TestImpl();
test.anotherMethod();
Of course you can access your methods as was answered above, but you should adhere to best practices in programming. So you if you can't add required methods to Interface1 create Interface2 that extends Inteface1 and finally add your methods.
You can call it if you cast to the implementing class, the one that implements that method In short:
Test test = new TestImpl();
// ... and later / somewhere else
((TestImpl) test).anotherMethod();
If you do not want to type cast it to the concrete class then you could make anotherMethod() as private method and call it inside testMethod() based on some logic.
for eg.
testMethod()
{
if(foo)
{
anotherMethod();
}
}
This is a workaround that you can use if you do not want to create new methods in child class , since you cannot call them using a parent class/interface reference.

suppress a singleton constructor in java with powermock

I'm trying to unit-test some classes that make use of a Singleton class whose constructor does some things I can't (and shouldn't) do from the unit-test environment. My ideal scenario would be to end up with the constructor completely suppressed and then stub out the other member methods that my test classes invoke. My problem is that I can't seem to get the constructor suppressed.
My understanding of a way to solve this would be something like the following:
public class MySingleton extends AbstractSingletonParent {
public final static MySingleton Only = new MySingleton();
private MySingleton(){
super(someVar); // I want the super-class constructor to not be called
//
//more code I want to avoid
}
public Object stubbedMethod() {}
}
public class ClassToBeTested {
public void SomeMethod(){
Object o = MySingleton.Only.stubbedMethod();
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(MySingleton.class)
public class TestClass {
#Test
public void SomeTest() {
suppress(constructor(MySingleton.class));
mockStatic(MySingleton.class);
PowerMock.replay(MySingleton.class);
// invoke ClassToBeTested, etc
PowerMock.verify(MySingleton.class);
//make some assertions
}
}
Unfortunately during the createMock invocation, the MySingleton constructor is hit, and it still calls the super constructor.
Am I doing something silly? I found an example on the web doing almost exactly this, but it was using a deprecated suppressConstructor method. Despite the deprecation I tried that, too, to no avail...
Is what I'm trying to do possible? If so, what am I doing wrong?
*Edited version now works.
You need to annotate TestClass with the #PrepareForTest annotation so it has a chance to manipulate the bytecode of the singletons.
Also, the superclass ctor supression signature should include somevar's class; right now you're just suppressing the default ctor.
See the #PrepareForTest API docs. Here's a blog post with some more details as well.
FWIW, it's working for me:
#RunWith(PowerMockRunner.class)
#PrepareForTest({EvilBase.class, NicerSingleton.class})
public class TestEvil {
#Test
public void testEvil() {
suppress(constructor(EvilBase.class));
assertEquals(69, EvilBase.getInstance().theMethod());
}
#Test
public void testNice() {
suppress(constructor(EvilBase.class));
suppress(constructor(NicerSingleton.class));
assertEquals(42, NicerSingleton.getInstance().theMethod());
}
}
How about you set the instance field ('only' in your code) of your Singleton with an instance instantiated with the constructor you want (you can do all of this with the Reflection API or dp4j).
The motivating example of a dp4j publication discusses that.
I am not sure what is it that you are doing wrong. But on the design side, i can suggest you look into dependency injection i.e. DI.
For making your code testable, make use of DI. With DI you would pass the singleton class as an constructor argument to your test class. And now since you pass an argument, inside your test case you can create a custom implementation of the AbstractSingleton class and your test case should work fine.
With DI, your code will become more testable.

How do I use Powermockito to mock the construction of new objects when testing a method in an anonymous class?

I woud like to write a JUnit test to verify that the code below uses a BufferedInputStream:
public static final FilterFactory BZIP2_FACTORY = new FilterFactory() {
public InputStream makeFilter(InputStream in) {
// a lot of other code removed for clarity
BufferedInputStream buffer = new BufferedInputStream(in);
return new CBZip2InputStream(buffer);
}
};
(FilterFactory is an interface.)
My test thus far looks like this:
#Test
public void testBZIP2_FactoryUsesBufferedInputStream() throws Throwable {
InputStream in = mock(InputStream.class);
BufferedInputStream buffer = mock(BufferedInputStream.class);
CBZip2InputStream expected = mock(CBZip2InputStream.class);
PowerMockito.spy(InputHelper.BZIP2_FACTORY); // This line fails
whenNew(BufferedInputStream.class).withArguments(in).thenReturn(buffer);
whenNew(CBZip2InputStream.class).withArguments(buffer).thenReturn(expected);
InputStream observed = InputHelper.BZIP2_FACTORY.makeFilter(in);
assertEquals(expected, observed);
}
The call to PowerMockito.spy raises an exception with this message:
org.mockito.exceptions.base.MockitoException:
Mockito cannot mock this class: class edu.gvsu.cis.kurmasz.io.InputHelper$1
Mockito can only mock visible & non-final classes.
What should I be using instead of PowerMocktio.spy to set up the calls to whenNew?
The message is pretty obvious: You can't mock non-visible and final classes. Short answer : Create a named class of your anonymous one, and test this class instead!
Long answer, let's dig why !
An anonymous class is final
You instantiate an anonymous class of FilterFactory, when the compiler sees an anonymous class, it creates a final and package visible class. So the anonymous class is not mockable through standard mean i.e. through Mockito.
Mocking anonymous class : possible but BRITTLE if not HACKY
OK, now suppose you want to be able to mock this anonymous class through Powermock. Current compilers compile anonymous class with following scheme :
Declaring class + $ + <order of declaration starting with 1>
Mocking anonymous class possible but brittle (And I mean it)
So supposing the anonymous class is the eleventh to be declared, it will appear as
InputHelper$11.class
So you could potentially prepare for test the anonymous class:
#RunWith(PowerMockRunner.class)
#PrepareForTest({InputHelper$11.class})
public class InputHelperTest {
#Test
public void anonymous_class_mocking works() throws Throwable {
PowerMockito.spy(InputHelper.BZIP2_FACTORY); // This line fails
}
}
This code will compile, BUT will eventually be reported as an error with your IDE. The IDE probably doesn't know about InputHelper$11.class. IntelliJ who doesn't use compiled class to check the code report so.
Also the fact that the anonymous class naming actually depends on the order of the declaration is a problem, when someone adds another anonymous class before, the numbering could change.
Anonymous classes are made to stay anonymous, what if the compiler guys decide one day to use letters or even random identifiers!
So mocking anonymous classes through Powermock is possible but brittle, don't ever do that in a real project!
EDITED NOTE : The Eclipse compiler has a different numbering scheme, it always uses a 3 digit number :
Declaring class + $ + <pad with 0> + <order of declaration starting with 1>
Also I don't think the JLS clearly specify how the compilers should name anonymous classes.
You don't reassign the spy to the static field
PowerMockito.spy(InputHelper.BZIP2_FACTORY); // This line fails
whenNew(BufferedInputStream.class).withArguments(in).thenReturn(buffer);
whenNew(CBZip2InputStream.class).withArguments(buffer).thenReturn(expected);
InputStream observed = InputHelper.BZIP2_FACTORY.makeFilter(in);
PowerMockito.spy returns the spy, it doesn't change the value of InputHelper.BZIP2_FACTORY. So you would need to actually set via reflection this field. You can use the Whiteboxutility that Powermock provide.
Conclusion
Too much trouble to just test with mocks that the anonymous filter uses a BufferedInputStream.
Alternative
I would rather write the following code:
An input helper that will use the named class, I don't use the interface name to make clear to the user what is the intent of this filter!
public class InputHelper {
public static final BufferedBZIP2FilterFactory BZIP2_FACTORY = new BufferedBZIP2FilterFactory();
}
And now the filter itself :
public class BufferedBZIP2FilterFactory {
public InputStream makeFilter(InputStream in) {
BufferedInputStream buffer = new BufferedInputStream(in);
return new CBZip2InputStream(buffer);
}
}
Now you can write a test like this :
#RunWith(PowerMockRunner.class)
public class BufferedBZIP2FilterFactoryTest {
#Test
#PrepareForTest({BufferedBZIP2FilterFactory.class})
public void wraps_InputStream_in_BufferedInputStream() throws Exception {
whenNew(CBZip2InputStream.class).withArguments(isA(BufferedInputStream.class))
.thenReturn(Mockito.mock(CBZip2InputStream.class));
new BufferedBZIP2FilterFactory().makeFilter(anInputStream());
verifyNew(CBZip2InputStream.class).withArguments(isA(BufferedInputStream.class));
}
private ByteArrayInputStream anInputStream() {
return new ByteArrayInputStream(new byte[10]);
}
}
But could eventually avoid powermock stuff for this test scenario if you force the CBZip2InputStream to only accept BufferedInputStream. Usually using Powermock means something is wrong with the design. In my opinion Powermock is great for legacy softwares, but can blind developers when designing new code; as they are missing the point of OOP's good part, I would even say they are designing legacy code.
Hope that helps !
Old post, but you don't need to create a named class - use wildcards instead as mentioned in this post powermock mocking constructor via whennew() does not work with anonymous class
#PrepareForTest(fullyQualifiedNames = "com.yourpackage.containing.anonclass.*")
You need to run the test using the PowerMockito runner, and you need to tell the framework which class(es) should have custom behaviour. Add the following class annotations on your test class:
#RunWith(PowerMockRunner.class)
#PrepareForTest({ BufferedInputStream.class })
I just came around the same problem. So according to the documentation of constructor mocking you need to prepare the class, which will create the evil class(es). In your case the evil classes are BufferedInputStream and CBZip2InputStream, and the creator of them is an anonymous class, which cannot be defined in PrepareForTest annotation. So I had to do the same as you did (hmm, just saw your comment), I moved the anonymous class to named class.

How can I test final and static methods of a utility project?

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.

Categories