How to avoid mocking interface default methods with EasyMock? - java

I have an interface having default methods. These refer to non-default methods and I want to mock only those.
Example:
public interface InterfaceWithDefaultMethod {
public String getTestString();
public default String getCombinedString() {
return "Test" + getTestString();
}
}
I only want to mock getTestString()
EasyMock.mock(InterfaceWithDefaultMethod.class) does produce a mock class where all methods are mocked, i.e. getCombinedString is not being delegated to getTestString().

The problem can be solved by creating a dummy implementation of the interface and to partial-mock this dummy implementation.
private static class InterfaceMock implements InterfaceWithDefaultMethod {
#Override
public String getTestString() {
return null;
}
}
private InterfaceWithDefaultMethod testedInterface;
#Before
public void setup() {
testedInterface = createMockBuilder(InterfaceMock.class)
.addMockedMethod("getTestString")
.createMock();
resetToNice(testedInterface);
expect(testedInterface.getTestString()).andStubReturn("First");
replay(testedInterface);
}

Related

Testing concrete methods in abstract classes using subclasses

abstract class BaseClass{
private final Dependency dep;
BaseClass(final Dependency dep){
this.dep = dep;
}
abstract void toBeImplementedBySubclasses();
public int concreteMethod(){
//Do some processing
return any_integer;
}
}
class DerivedOne{
#Inject
DerivedOne(final Dependency dep){
super(dep);
}
public void toBeImplementedBySubclasses(){
//DO SOMETHING RELEVANT TO DERIVED ONE IMPLEMENTATION
}
}
class DerivedTwo{
#Inject
DerivedOne(final Dependency dep){
super(dep);
}
public void toBeImplementedBySubclasses(){
//DO SOMETHING RELEVANT TO DERIVED TWO IMPLEMENTATION
}
}
I want to test concrete methods in abstract class.
Is it ok if I test the concrete methods in base class in the unit test for any of the two derived classes, or is there any other way?
So, if write test for DerivedOne class, it will include test for all methods AND the concrete method of the base class as well.
I know there is a thing "Mockito.CALLS_REAL_METHODS", using which we can test abstract classes, but in my case my base class has some dependencies which I initalise/inject using super() insider constructor of my derived classes, so I cant be doing it using CALLS_REALS_METHODS
There are two options which immediately come to mind here.
Firstly, you could write an abstract test class, which handles testing these methods, and then the test classes for your concrete implementations do the rest. For example:
public abstract class YourAbstractClassTest {
protected abstract YourAbstractClass getInstance();
#Test
public void testThing() {
final YourAbstractClass instance = this.getInstance();
instance.callMethod();
Assertions.assertTrue(instance.someProperties());
}
}
Alongside:
public class ConcreteSubclassTest extends YourAbstractClassTest {
private final ConcreteSubclass instance = new ConcreteSubclass();
#Override
protected YourAbstractClass getInstance() {
return this.instance;
}
#Test
public void moreTesting() {
this.instance.implementationSpecificMethod();
}
}
You could also create a dummy subclass in a test class for it:
public class AbstractClassTest {
private final AbstractClass instance = new AbstractClass() {
#Override
public void abstractMethod() {
throw new UnsupportedOperationException();
}
}
#Test
public void testThing() {
this.instance.concreteMethod();
// Just make sure this doesn't ever go near the
// methods you dummied up above...
}
}

Stubbing the call of a super class method using Mockito(V 1.9.5)

I am trying to test a method whom depending on some conditions will execute its code or its super class's one.
Here is the code of the class and its parent:
public class ParentClass {
public Object doStuff(Parameters parameters) {
// do some business stuff
return parentResult;
}
}
The inherited class's one:
public class InheritedClass extends ParentClass {
#Override
public Object doStuff(Parameters parameters) {
if (parameters.getCondition()) {
return super.doStuff(parameters);
}
//do some business stuff
return inheritedResult;
}
}
So, when trying to test the case when the parameters.getCondition() is true, I have to mock the call on the super method and verify it.
But when I do this (mocking the call for the super.doStuff()), I also mock the call to the InhertitedClass.doStuff().
Here's the solution I tried:
#RunWith(MockitoJUnitRunner.class)
public class InheritedClassTest {
#Mock
private Parameters parameters;
#Spy
private InheritedClass inherited = new InheritedClass();
#Test
public void testDoStuff(Object parameters) throws Exception {
given(parameters.getCondition()).willReturn(true);
doCallRealMethod().doReturn(value).when(inherited).doStuff(parameters);
Mockito.verify(inherited, times(2)).doStuff(parameters);
}
}
I also tried this stubbing:
when(inherited.doStuff(parameters)).thenCallRealMethod().thenReturn(value);
and this one:
given(((ParentClass)inherited).doStuff(parameters)).willReturn(value);
In all this cases, the code of the parent class was really executed.
So, I was wondering if there is any efficient way to mock the call of the super class method using mockito?
You can use Mockito's spy(), which you already tried to do. But I think a different way of using spy() will make it work.
ParentClass.java
public class ParentClass {
public String doStuff(final String parameters) {
return "parent";
}
}
InheritedClass.java
public class InheritedClass extends ParentClass {
#Override
public String doStuff(final String parameters) {
if (parameters.equals("do parent")) {
return super.doStuff(parameters);
}
return "child";
}
}
InheritedClassTest.java
public class InheritedClassTest {
#Test
public void testDoStuff() throws Exception {
final InheritedClass inheritedClass = Mockito.spy(new InheritedClass());
Mockito.doReturn("mocked parent").when((ParentClass)inheritedClass).doStuff(Mockito.eq("do parent"));
final String result = inheritedClass.doStuff("do parent");
assertEquals("mocked parent", result);
assertNotEquals("parent", result);
final String resultChild = inheritedClass.doStuff("aaa");
assertEquals("child", resultChild);
}
}
However, I do not think using spy() is a good practice. I would personally refactor your code.

Mock inherited protected method

I here have a simplified version of my problem. Class A has a protected method. Class B inherits this method.
public class A{
protected String getString(){
//some Code
}
}
public class B extends A{
public void doSomething(){
//someCode
String result = getString();
}
}
I now write a Unit-Test with Mockito, which is in another package-test and I want to test the doSomething() method. To do that, I need to mock the getString()-call. Since the method is protected and my test-class is in a differnet package, I can't use doReturn(...).when(classUnderTest).getString(). The thing is, that I spy on class B. So I can't use mock(new B(), Mockito.CALLS_REAL_METHODS).
I tried getting the protected method via Reflection:
Method getString = classUnderTest.getClass().getDeclaredMethod("getString");
getString.setAccessible(true);
But I then don't know how to use this inside doReturn().
You can use 'override and subclass'
B b = new B() {
#Override
protected String getString() {
return "FAKE VALUE FOR TESTING PURPOSES";
};
};
There might be a cleaner way of doing this, but here goes...
Create a mock for "A"
Create another class that extends B and overrides the method
Make the overridden method call the mock
For example...
private A partialMock;
private B classUnderTest;
#Before
public void setup() {
partialMock = mock(A.class);
classUnderTest = new B() {
#Override
protected String getString() {
return partialMock.getString();
}
};
}
#Test
public void shouldDoSomething() {
when(partialMock.toString()).thenReturn("[THE MOCKED RESPONSE]");
classUnderTest.doSomething();
// ...verify stuff...
}
Obviously you don't even need to use mocking, you can just return something directly from the overridden method.
Something like following worked for me, using doReturn() and Junit5's ReflectionSupport.
[Note: I tested on Mockito 3.12.4]
var a = spy(new A);
ReflectionSupport.invokeMethod(
a.getClass().getSuperclass().getDeclaredMethod("getString"),
doReturn("FAKE VALUE FOR TESTING PURPOSES").when(a));

Mockito - Mock base implementation while testing derived class implementation of same method

I am using Mockito for some unit testing. I have the following classes:
public class Base {
public void say() {
System.out.println("Base"); // some work in the base class
}
}
public class Derived extends Base {
#Override
public void say() {
super.say(); // do the base class work
System.out.println("Derived"); // some additional work in the derived class
}
}
Now I want to test the Derived class's say() method while mocking the base say() method. I followed the suggestion here: Mockito How to mock only the call of a method of the superclass and I now have.
public class DerivedTest {
#Test
public void testSay() {
Derived obj = Mockito.spy(new Derived());
Mockito.doNothing().when((Base)obj).say();
obj.say();
// assert only "Derived" was output
}
}
But this doesn't work as it mocks both the base and the derived class implementation. I want to test just the extra logic in the derived class.
How can I do this.
Update: My solution
Since I couldn't change the base class as suggested, I modified my derived class to extract all the extra logic in a a separate method and just tested that method.
public class Derived extends Base {
#Override
public void say() {
super.say(); // do the base class work
doAdditionalWork(); // some additional work in the derived class
}
void doAdditionalWork() {
System.out.println("Derived");
}
}
public class DerivedTest {
#Test
public void testDoAdditionalWork() {
Derived obj = new Derived();
obj.doAdditionalWork();
// assert only "Derived" was output
}
}
This means that I am still not testing the derived say() method but given that the logic there is quite simple now, I hope I can be excused for this. The other downside is that I can't have a visibility stricter than package-private for the doAdditionalWork() method.
When you spy an object, you completely replace the implementation of the method(s) which you've defined a mock behavior for. So, as you noted in the question, this would not work.
One trick around this is to extract an additionalBehavior() method, and test it only, without spying or mocking:
public class Base {
public void say() {
System.out.println("Base"); // some work in the base class
additionalBehavior();
}
protected void additionalBehavior() {
// No implementation. Alternatively - make it abstract
}
}
public class Derived extends Base {
#Override
protected void additionalBehavior() {
System.out.println("Derived"); // some additional work in the derived class
}
}
public class DerivedTest {
#Test
public void testAdditionalBehavior() {
Derived obj = new Derived();
obj.additioanlBehavior();
// assert that "Derived" was the output
}
}

mock of autowired field is null in unit test

Does anyone know why in this example, when running "ATest", I get a null on the line "return b.getBAutoWiredObject().getString();"
Any insight on this would be appreciated.
#RunWith(MockitoJUnitRunner.class)
public class ATest {
#Mock
private A a;
#Test
public void testMethod() {
String testedString = a.method();
assertEquals("blah", testedString);
}
}
#Service("A")
public class A {
public String method() {
B b = new B();
return b.getBAutoWiredObject().getString();
}
}
#Component
public class B {
#Autowired
#Qualifier("Bautowire")
private BAutoWiredObject bAutoWiredObject;
public BAutoWiredObject getBAutoWiredObject() {
return bAutoWiredObject;
}
}
#Service("Bautowire")
public class BAutoWiredObject {
private String string = new String("blah");
public void getString() {
return string;
}
}
Typically, the answer would be it's null because you created the B instance yourself. Spring is not involved in the least, so it hasn't autowired anything.
In this case, your A object is a #Mock and mocks are typically implemented to return null in any method that has a return type that is a reference type. Your method() implementation isn't actually getting called. The mock's implementation is.
This is all assuming your test would actually compile and was valid with a #Test annotated method.
assertEquals(testedString, "blah");
should be
assertEquals("blah", testedString);
The first argument should be the expected value and the second should be the actual value.

Categories

Resources