How to mock Abstract class method in a class to be tested - java

There is an abstract class
public abstract class BaseProcessor {
public BooksTransaction getBooksTransaction() {
return booksTransaction;
}
}
There is another final class which is to be tested using Junit
public final class CreateOrganisationProcessor extends BaseProcessor {
public boolean process() throws Exception { //method to be tested
request = new CreateOrganisationRequest(IntegrationSystems.valueOf(getBooksTransaction().getSource()),
IntegrationSystems.valueOf(getBooksTransaction().getDestination()), getBooksTransaction());
request.setRequestTypes(getRequestTypes());
return true;
}
}
I tried spying the BaseProcessor class and mocking getBooksTransaction method to return BooksTransaction Object.
Code:
#Test
public void testProcess() throws Exception {
BaseProcessor spy = Mockito.spy(new CreateOrganisationProcessor());
BooksTransaction booksTransaction = new BooksTransaction();
booksTransaction.setReferenceID(DEFAULT_REFERENCE_ID);
Mockito.doReturn(booksTransaction).when(spy).getBooksTransaction();
}
Here, BooksTransaction is an JPA Entity class.
However, when I run the test case, the mock does not seem to be working, it does not return a BooksTransaction Object.
It neither throws an exception, nor any error.
I would like to know the right way to spy this method so that it returns me an object of BooksTransaction as per my mock.
I am new to Mockito, any help would be appreciable.
Thanks in advance.

It's funny that you got 5 up-votes for a question that does not even compile to begin with... I have simplified it just a bit, so that I could actually compile it, since I do not know your structure or can't even guess it correctly.
But the very first point you should be aware of is that Mockito can't by default mock final classes; you have a comment under your question that shows how to enable that.
#Getter
static abstract class BaseProcessor {
private BooksTransaction BooksTransaction;
}
#Getter
static class CreateOrganisationProcessor extends BaseProcessor {
CreateOrganisationRequest request;
public boolean process() { //method to be tested
request = new CreateOrganisationRequest(getBooksTransaction());
return true;
}
public CreateOrganisationRequest getRequest() {
return request;
}
}
#RequiredArgsConstructor
#Getter
static class BooksTransaction {
private final String testMe;
}
#Getter
#RequiredArgsConstructor
static class CreateOrganisationRequest {
private final BooksTransaction booksTransaction;
}
And here is a test that does work:
#Test
public void test() {
CreateOrganisationProcessor org = new CreateOrganisationProcessor();
CreateOrganisationProcessor spy = Mockito.spy(org);
System.out.println(spy);
BooksTransaction booksTransaction = new BooksTransaction("go!");
Mockito.doReturn(booksTransaction).when(spy).getBooksTransaction();
spy.process();
BooksTransaction mocked = spy.getRequest().getBooksTransaction();
Assert.assertEquals(mocked.getTestMe(), "go!");
}
And now think about it, you say in a comment : //method to be tested but you are not even calling it in your test, sounds fishy doesn't it? Than that method is defined in CreateOrganisationProcessor, but you are assigning your spy to:
BaseProcessor spy = Mockito.spy(new CreateOrganisationProcessor());
So now you can't even call process anymore on that spy reference, since it is not defined in BaseProcessor.

Related

Mocking constructor using PowerMockito doesn't work

I want to test a method which creates an object of another class using it's parameterized constructor. Even though I've mocked the constructor of MyClass, it makes the third party library which is in constructor implementation and results in the error. I'm using Mockito/PowerMockito.
public class MyClass{
private MyObj obj;
MyClass (String profile)
{
//some 3rd party library call
obj = thridPartyLib.someMethod(profile);
}
public String someMethod(){
return obj.someExternalCall();
}
}
Class which I want to test
public class ClassTobeTested{
public void execute(){
//some code
// ......
MyClass myClass = new MyClass(profile);
myclass.someMethod();
}
}
What I tried so far - classUnderTest.execute() ends up calling the thridPartyLib.someMethod(profile); which is part of MyClass constructor.
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClass.class)
public class ClassTobeTestedTest {
private MyClass mockMyClass;
private ClassTobeTested classUnderTest;
#Before
public void init() {
classUnderTest = new ClassTobeTested();
mockMyClass = PowerMockito.mock(MyClass.class);
}
#Test
public void testExecute(){
PowerMockito.whenNew(MyClass.class)
.withArguments(Mockito.any())
.thenReturn(mockMyClass);
classUnderTest.execute();
}
}
Your code will work only if you are working with a spy or mock of classUnderTest. Try this. This should work
#RunWith(PowerMockRunner.class)
#PrepareForTest( {MyClass.class, ClassTobeTested.class })
public class ClassTobeTestedTest {
private MyClass mockMyClass;
private ClassTobeTested classUnderTest;
#Before
public void init() {
classUnderTest = spy(new ClassTobeTested());
mockMyClass = PowerMockito.mock(MyClass.class);
}
#Test
public void testExecute() throws Exception {
PowerMockito.whenNew(MyClass.class)
.withArguments(Mockito.any())
.thenReturn(mockMyClass);
classUnderTest.execute();
}
}
The pain might suggest another approach. Consider injecting a Factory into ClassTobeTested which knows how to create an instance of MyObj. For example:
class MyObjFactory {
MyObj create(String profile) {
return new MyClass(profile);
}
}
then
public class ClassTobeTested {
private final MyObjFactory factory;
public ClassTobeTested(MyObjFactory factory) {
this.factory = factory;
}
public void execute(){
//some code
// ......
// MyClass myClass = new MyClass(profile);
MyClass myClass = factory.create(profile);
myclass.someMethod();
}
}
so the unit test becomes simpler with only having to mock the Factory and have it return a mocked MyClass instance. Then it's simple to verify myclass.someMethod() was invoked as expected.

EasyMock #Mock is not working same as createMock for abstract classes

As per the answer here, #Mock annotation and createMock are same from functionality view. But, I am facing a strange issue while using these. Little background here.
I have to test ClassUnderTest which calls method from Abstractclass. When I should call from the unit test to ClassUnderTest, I expect the Abstractclass method to be called.
`
public abstract AbstractClass {
public void addValue(int a, int b) {
// Invoking another method which is abstract.
};
}
public class ClassUnderTest {
public Abstractclass obj;
public ClassUnderTest(Abstractclass obj) {
// Parameterized constructor.
}
public MethodToTest(){
object.addValue(1, 2); // Calls the method.
}
}
#RunWith(EasyMockRunner.class)
public class TestFile {
#Mock
private AbstractClass concrete;
#Test
public void testMethod() {
concrete = EasyMock.createMock(AbstractClass.class);
concrete.addValue(1,2);
EasyMock.expectLastCall().once();
EasyMock.replay();
new ClassUnderTest().methodToTest();
EasyMock.verify() // The code under scan.
}
}
`
I am facing these issues:
When I am using #Mock annotation, EasyMock verify throws an error saying Abstractclass.addValue() expectation is not fulfilled.
But, when I remove #Mock annotation, it works fine and no error is there.
For Non abstract classes, #Mock is working fine for me.
Could anybody please explain this behavior?
Your real code must be different from this one. Both should behave exactly the same. Otherwise it is a bug. I tried your code (applying a lot of fixes. You should post correctly running examples next time). It works perfectly. Here is it
abstract class AbstractClass {
public abstract void foo();
public void addValue(int a, int b) {
foo();
}
}
class ClassUnderTest {
private AbstractClass obj;
public ClassUnderTest(AbstractClass obj) {
this.obj = obj;
}
public void methodToTest(){
obj.addValue(1, 2); // Calls the method.
}
}
#RunWith(EasyMockRunner.class)
public class TestFile {
#Mock
private AbstractClass concrete;
#Test
public void testMethod() {
// concrete = EasyMock.createMock(AbstractClass.class);
concrete.addValue(1,2);
EasyMock.replay();
new ClassUnderTest(concrete).methodToTest();
EasyMock.verify(); // The code under scan.
}
}
To be super clear. These 4 mean exactly the same thing:
// 1. Calling once the void method
concrete.addValue(1,2);
// 2. Calling once the void method and then using expectLastCall()
concrete.addValue(1,2);
expectLastCall();
// 3. Calling once the void method and then expect once
concrete.addValue(1,2);
expectLastCall().once();
// 4. Calling once the void method and then expect one time
concrete.addValue(1,2);
expectLastCall().time(1);

How to Mock private method which is called from the constructor using PowerMockito

Example of the problem:
class ToBeTested {
private MyResource myResource;
public toBeTested() {
this.myResource = getResource();
}
private MyResource getResource() {
//Creating My Resource using information form a DB
return new MyResource(...);
}
}
I would like to mock the getResource() so I would be able to provide a mock instance of MyResource. All the examples I found on how to mock a private method are based on first creating the ToBeTested instance and then replace the function but since it's being called from the constructor in my case it's to late.
Is it possible to mock the private function to all instances in advance of creating them?
Not directly but, you can suppress and then simulate with power mockito
#RunWith(PowerMockRunner.class)
#PrepareForTest(ToBeTested .class)
public class TestToBeTested{
#before
public void setup(){
suppress(method(ToBeTested.class, "getResource"));
}
#Test
public void testMethod(){
doAnswer(new Answer<Void>() {
#Override
public MyResource answer(InvocationOnMock invocation) throws Throwable {
return new MyResource();
}
}).when(ToBeTested.class, "getResource");
}
ToBeTested mock = mock(ToBeTested.class);
mock.myMethod();
//assert
}

Mockito - Impossible stubbing mocked object

I am newbie in Java world, but it is very hard understand why not can I stub method of a mocked object...
#RunWith(MockitoJUnitRunner.class)
public class ChildBLLIT extends BaseInteractorIT {
#InjectMocks
private ChildBLL ChildBLL = Mockito.mock(ChildBLL.class);
#Before
public void setUp() {
ChildBLL.engine = engineMock;
}
/**
* Test of getZipStatistics method, of class ChildBLL.
*/
#Test
public void testGetZipStatistics() {
final String testZipStatisticsText = "DummyZipStatistics";
//This method will throw the null pointer exception
when(ChildBLL.engine.getZIPStatistics()).thenReturn(testZipStatisticsText);
ChildBLL.getZipStatistics();
verify(ChildBLL.engine).getZIPStatistics();
}
}
When I try to stub the getZIPStatistics() method I get always a null pointer exception, of course I get, because in the getZIPStatistics() method there is an private object, which is not mocked... it seems to me the Mockito does not mocking the private fields... and unfortunately this is from another project:
public class BaseIT {
#Mock
protected static FromOtherProject engineMock;
#Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
}
Here I mocked the engine variable, but then how can I mock/stub the getZIPStatistics() method? This is this method:
public class FromOtherProject {
//...
public final String getZIPStatistics() {
return ZIPStatistics.toString();
}
}
What can I do?
Let's assume a simple class...
public class Account {
public String getPassword() {
return "abc";
}
}
...and simple class that contains it...
public class AccountHolder {
private Account account;
public String getAccountPassword() {
return this.account.getPassword();
}
}
So now we have a simple base class for all Account based tests...
public class AccountBasedTest {
#Mock
protected Account account;
}
...and a class that actually tests the AccountHolder...
#RunWith(MockitoJUnitRunner.class)
public class AccountHolderTest extends AccountBasedTest {
#InjectMocks
private AccountHolder accountHolder;
#Test
public void getAccountPasswort_must_return_account_password() {
Mockito.when( this.account.getPassword() ).thenReturn ("xyz");
Assert.assertEquals("xyz", this.accountHolder.getAccountPassword());
}
}
And that's all. The #InjectMocks, etc. annotations will also look in the superclasses, so you get your mocked account and that account will be put into your AccountHolder. No need to call MockitoAnnotations.initMocks. It shouldn't hurt, but it's not needed because you are using the MockitoJUnitRunner already, which does exactly that.

java.lang.IllegalStateException: missing behavior definition for the preceding method call getMessage("title")

I'm using EasyMock(version 2.4) and TestNG for writing UnitTest.
I have a following scenario and I cannot change the way class hierarchy is defined.
I'm testing ClassB which is extending ClassA.
ClassB look like this
public class ClassB extends ClassA {
public ClassB()
{
super("title");
}
#Override
public String getDisplayName()
{
return ClientMessages.getMessages("ClassB.title");
}
}
ClassA code
public abstract class ClassA {
private String title;
public ClassA(String title)
{
this.title = ClientMessages.getMessages(title);
}
public String getDisplayName()
{
return this.title;
}
}
ClientMessages class code
public class ClientMessages {
private static MessageResourse messageResourse;
public ClientMessages(MessageResourse messageResourse)
{
this.messageResourse = messageResourse;
}
public static String getMessages(String code)
{
return messageResourse.getMessage(code);
}
}
MessageResourse Class code
public class MessageResourse {
public String getMessage(String code)
{
return code;
}
}
Testing ClassB
import static org.easymock.classextension.EasyMock.createMock;
import org.easymock.classextension.EasyMock;
import org.testng.Assert;
import org.testng.annotations.Test;
public class ClassBTest
{
private MessageResourse mockMessageResourse = createMock(MessageResourse.class);
private ClassB classToTest;
private ClientMessages clientMessages;
#Test
public void testGetDisplayName()
{
EasyMock.expect(mockMessageResourse.getMessage("ClassB.title")).andReturn("someTitle");
clientMessages = new ClientMessages(mockMessageResourse);
classToTest = new ClassB();
Assert.assertEquals("someTitle" , classToTest.getDisplayName());
EasyMock.replay(mockMessageResourse);
}
}
When I'm running this this test I'm getting following exception:
java.lang.IllegalStateException: missing behavior definition for the preceding method call getMessage("title")
While debugging what I found is, it's not considering the mock method call
mockMessageResourse.getMessage("ClassB.title") as it has been called from the construtor (ClassB object creation).
Can any one please help me how to test in this case.
Thanks.
You need to call EasyMock.replay(mock) before calling the method under test. After calling the method under test you can call EasyMock.verify(mock) to verify the mock is called.
Next you need to add another expect call with the "title" argument since you call it twice.
Code:
EasyMock.expect(mockMessageResourse.getMessage("title")).andReturn("title");
EasyMock.expect(mockMessageResourse.getMessage("ClassB.title")).andReturn("someTitle");
EasyMock.replay(mockMessageResourse);
clientMessages = new ClientMessages(mockMessageResourse);
classToTest = new ClassB();
Assert.assertEquals("someTitle" , classToTest.getDisplayName());
EasyMock.verify(mockMessageResourse);
In my case, it was caused by the omission of a return value specification (andReturn(...)).
http://www.smcmaster.com/2011/04/easymock-issue-1-missing-behavior.html for more details.
This can have various causes (someMock is the name of your mocked Object in this answer).
On the one side it can be that you need to expect the call via
expect(someMock.someMethod(anyObject()).andReturn("some-object");
like in Reda's answer.
It can also be that you forgot to call replay(someMock) before you used the mock, like you can see in Julien Rentrop's answer.
A last thing that is possible that wasn't mentioned here is that you used the mock somewhere else before in a test and forgot to reset the mock via reset(someMock).
This can happen if you have multiple Unit Tests like this:
private Object a = EasyMock.createMock(Object.class);
#Test
public void testA() throws Exception {
expect(a.someThing()).andReturn("hello");
replay(a);
// some test code and assertions etc. here
verify(a);
}
#Test
public void testB() throws Exception {
expect(a.someThing()).andReturn("hello");
replay(a);
// some test code and assertions etc. here
verify(a);
}
This will fail on one test with the IllegalStateException, because the mock a was not reset before being used in the next test. To solve it you can do the following:
private Object a = EasyMock.createMock(Object.class);
#Test
public void testA() throws Exception {
expect(a.someThing()).andReturn("hello");
replay(a);
// some test code and assertions etc. here
verify(a);
}
#Test
public void testB() throws Exception {
expect(a.someThing()).andReturn("hello");
replay(a);
// some test code and assertions etc. here
verify(a);
}
#After
public void tearDown() throws Exception {
reset(a); // reset the mock after each test
}
You should put your call to replay after the expect calls, and before you use your mock. In this case you should change your test to something like this:
#Test
public void testGetDisplayName()
{
EasyMock.expect(mockMessageResourse.getMessage("ClassB.title")).andReturn("someTitle");
EasyMock.replay(mockMessageResourse);
clientMessages = new ClientMessages(mockMessageResourse);
classToTest = new ClassB();
Assert.assertEquals("someTitle" , classToTest.getDisplayName());
}
For me, this exception was occurring because the method I was trying to stub was final (something I hadn't realized).
If you want to stub a final method you'll need to use Powermock.

Categories