Java Mockit : How to Mock a generic class method in JMockit - java

Hi I have the following classes
public class DataAccessLayer<T> {
public T getData(Class<?> dataInfoType ,Integer id){
//Some logic here
}
}
public class ServiceLayer{
//this method has to be tested
public Integer testingMethode{
//The following line should be mocked
UtilClass info = new DataAccessLayer<UtilClass>().getData(UtilClass.class, 1);
retutn info.getSomeFieldWithIntegerValue();
}
}
I want to write test cases for testingMethode for that I need to mock the getData() method in DataAccessLayer<T>
Is it possible with jmockit to mock a Template(Generic ) class?

A generic class can be mocked the same way a non-generic one:
#Test
public void example(#Mocked final DataAccessLayer<UtilClass> mock)
{
final UtilClass data = new UtilClass(123);
new Expectations() {{ mock.getData(UtilClass.class, 1); result = data; }};
int result = new ServiceLayer().testingMethode();
assertEquals(123, result);
}

(I can only really answer for Mockito, as that is what I am most familiar with; but the same principle should be applicable in other mocking frameworks).
Firstly, you need to be able to inject a DataAccessLayer<UtilClass> into ServiceLayer, e.g.
class ServiceLayer {
private final DataAccessLayer<UtilClass> dal;
ServiceLayer(DataAccessLayer<UtilClass> dal) {
this.dal = dal;
}
public Integer testingMethode() {
UtilClass info = dal.getData(UtilClass.class, 1);
return info.getSomeFieldWithIntegerValue();
}
}
This breaks the static coupling to the DataAccessLayer<UtilClass> created by the use of the new.
Now, you can create a mocked instance of DataAccessLayer<UtilClass> by creating a non-generic subclass:
class UtilClassDataAccessLayer extends DataAccessLayer<UtilClass> {}
and then create a mock instance:
DataAccessLayer<UtilClass> mocked = mock(UtilClassDataAccessLayer.class);
Now, you can configure this mock as you need, and pass it into the ServiceLayer:
ServiceLayer serviceLayer = new ServiceLayer(mocked);

In JMockit there's actually no need to create a holding variable in the ServiceLayer class, nor is there a need to make a parameterized subclass of your DataLayer. The following test works just fine:
package com.example.dsohl;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import org.junit.Test;
import org.junit.runner.RunWith;
import mockit.Deencapsulation;
import mockit.Expectations;
import mockit.Mocked;
import mockit.Tested;
import mockit.integration.junit4.JMockit;
#RunWith(JMockit.class)
public class TestTest {
public static class UtilClass {
public Integer foo() {
return 5;
}
}
public static class DataLayer<T> {
public T getItem(Class<T> clazz, int itemId) {
return null;
}
}
public static class ServiceLayer {
public Integer testMethod() {
UtilClass util = new DataLayer<UtilClass>().getItem(UtilClass.class, 1);
return util.foo();
}
}
// Test really begins here
#Tested ServiceLayer svc;
#Mocked DataLayer<UtilClass> data;
#Mocked UtilClass util;
#Test
public void testDateSubtraction() throws Exception {
new Expectations() {
{
new DataLayer<UtilClass>(); result = data;
onInstance(data).getItem(UtilClass.class, 1); result = util;
util.foo(); result = 37;
}
};
Integer i = svc.testMethod();
assertThat(i, equalTo(37));
}
}
A few notes: First, my DataLayer.getItem() returns null so if the injection fails, we get a NullPointerException, nice and obvious. Obviously your code won't work like this; this is only to convince you.
Second, I use onInstance() so that we can be 100% certain that the result of the DataLayer constructor is what we are using in the next steps of the test. The default behaviour of Expectations on a #Mocked object is to record the expectation against any object of that class; this is how we are certain that it's our object that's being used. (Ordinarily I don't worry myself about this, but when using new I like to be certain.)
Finally, I'm omitting some other stuff I might do in cases like this, like use a Verifications block, etc. Just trying to be as straightforward as possible.
Enjoy!

Related

Mock inner final object

I am trying to write a test for pre-existing class.
class ClassToBeTested {
private final Obj1 a;
ClassToBeTested(String anotherVariable) {
a = new Obj1(anotherVariable);
}
public void methodToBeTested() {
if(invokeSomeOtherMethod()) {
a.getAnotherVariable().doSomething();
}
}
public boolean invokeSomeOtherMethod() {
// return true or false based on some logic
}
Obj1 getObj1() {
return a;
}
}
Below is my Test Class:
class TestClass {
#Test
public void testMethod() {
ClassToBeTested x = new ClassToBeTested("someString");
ClassToBeTested spyX = spy(x);
doReturn(false).when(spyX).invokeSomeOtherMethod();
spyX.methodToBeTested();
verify(spyX, times(1)).getObj1().doSomething();
}
}
This is my understanding:
Since the obj1 is private final object which is created in the class constructor, it neither be directly accessed in the test method nor force the spyObject to use a mocked version of obj1.
Also since verify() requires mocked version of obj1, it throws me an error:
Wanted But Not invoked: x.getObj1(), however there are otherInteractions with this mock: x.invokeSomeOtherMethod()
Is my understanding wrong? What would be the way to test testMoethod()?
You seem to not understand how to do proper dependency injection. You don't need to change all your code in order to make it easier to test - just use constructor telescoping for example:
class ClassToBeTested {
private final Obj1 a;
public ClassToBeTested(String anotherVariable) {
this(new Obj1(anotherVariable));
}
ClassToBeTested(Obj1 a) {
this.a = a;
}
Done. Now you have a package-protected constructor that you can use to insert an instance of a directly. And all your other production code can stay like it is.
In other words: don't "fix" your design problems by using mocking framework tricks.

Mocking method from protected abstract method

Here's my problem in detail.
Setup:
I have class A that has a private member variable of class B.
A method(method1) in class A calls a non-static method(method2)
in class B.
Class B actually inherits method2 from a protected abstract class C and does not override it.
Problem:
I'm writing a test for class A.
In the test I'm mocking the call to method2.
Sample Code:
B b = Mockito.mock(B.class);
A a = new A(b);
Mockito.when(b.method2()).thenReturn(MY_LIST);
Now when I call method1(which in turn calls method2), I get a
NullPointerException.
Sample Code:
a.method1();
I'm assuming that this call is completely independent of the implementation of method2 since I'm mocking it. Is that wrong ? If not, what am I doing wrong ?
PS: class C is protected and Class A is in a different package from class B and C.
I see that you are using Mockito in your test. I have recently used it on a project and I did a test project with the following.
First a service (A) with uses another class (B).
public class Service {
private NonStaticClass nonStatic;
public NonStaticClass getNonStatic() {
return nonStatic;
}
public void setNonStatic(NonStaticClass nonStatic) {
this.nonStatic = nonStatic;
}
public int useStaticService () {
return 2*StaticClass.staticMethod();
}
public Integer getLastUse () {
return this.nonStatic.getLastUse();
}
}
Then here is the (B) class:
public class NonStaticClass {
private Integer lastUse = new Integer(0);
public Integer getLastUse() {
return lastUse++;
}
}
In order to test everithing is working i created a test for it.
import static org.mockito.Mockito.when;
import junit.framework.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
#RunWith(MockitoJUnitRunner.class)
public class TestNonStaticMock {
private final Integer staticMethodOutput = 10;
#Mock
NonStaticClass mock = new NonStaticClass();
#InjectMocks
Service service = new Service();
#Before
public void before () {
setMock();
}
private void setMock() {
when(mock.getLastUse()).thenReturn(staticMethodOutput);
}
#Test
public void mockNonStaticMethod () {
Integer result = service.getLastUse();
System.out.println(result.toString());
Assert.assertEquals(staticMethodOutput, result);
}
}
Hope it can be usefull.

In testing in java how to check if a method of an interface is called or not?

I want to test this class which calls a method of interface using anonymous class.
public class ClassToTest
{
public void methodToTest()
{
InterefaceToMock interefaceToMockReference = new InterefaceToMock() {
#Override
public int methodToMock()
{
return 0;
}
};
interefaceToMockReference.methodToMock();
}
}
This is the interface
public interface InterefaceToMock
{
public int methodToMock();
}
I am using this approch to check it methodToMock is called or not
import static org.junit.Assert.*;
import org.junit.Test;
import mockit.FullVerificationsInOrder;
import mockit.Mocked;
import mockit.NonStrictExpectations;
public class TestAClass
{
#Mocked InterefaceToMock interefaceToMockReferenceMocked;
#Test
public void test1()
{
new NonStrictExpectations()
{
{
interefaceToMockReferenceMocked.methodToMock();times=1;
}
};
(new ClassToTest()).methodToTest();
new FullVerificationsInOrder(interefaceToMockReferenceMocked)
{
};
assertTrue(true);
}
}
But test case fails.
Can anyone help.
Your original test was almost correct. It declared the mock field as simply being #Mocked, which merely gives you a single mocked instance implementing the interface, and this is not the one used by the code under test. The JMockit API has another mocking annotation, however, which extends mocking to all implementation classes from a given base type, and by default affects all instances of said classes. So, the test should be changed as follows:
public class TestAClass
{
#Capturing InterfaceToMock anyImplementingInstance;
#Test
public void test1()
{
new ClassToTest().methodToTest();
new Verifications() {{
anyImplementingInstance.methodToMock();
}};
}
}
In the general case, if you have an class and you want to check whether a method on a Mock of that class is called, you use Mockito.verify.
For example:
public class AppTest {
#Test
public void testMe() {
final ITest iTest = Mockito.mock(ITest.class);
final CUT cut = new CUT(iTest);
cut.doStuff();
Mockito.verify(iTest).someStuff();
}
interface ITest {
void someStuff();
}
class CUT {
private final ITest iTest;
CUT(ITest iTest) {
this.iTest = iTest;
}
public void doStuff() {
iTest.someStuff();
}
}
}
Here, the test is whether ITest.someStuff() is called from CUT.doStuff().
Your example is undecipherable...

Mock a static method multiple times using JMockit within a JUnit test

I have a class with static methods that I'm currently mocking with JMockit. Say it looks something like:
public class Foo {
public static FooValue getValue(Object something) {
...
}
public static enum FooValue { X, Y, Z, ...; }
}
I have another class (let's call it MyClass) that calls Foo's static method; I'm trying to write test cases for this class. My JUnit test, using JMockit, looks something like this:
public class MyClassTest extends TestCase {
#NonStrict private final Foo mock = null;
#Test public void testMyClass() {
new Expectations() {
{
Foo.getValue((Object) any); result = Foo.FooValue.X;
}
};
}
myClass.doSomething();
}
This works fine and dandy, and when the test is executed my instance of MyClass will correctly get the enum value of Foo.FooValue.X when it calls Foo.getValue().
Now, I'm trying to iterate over all the values in the enumeration, and repeatedly run the test. If I put the above test code in a for loop and try to set the result of the mocked static method to each enumeration value, that doesn't work. The mocked version of Foo.getValue() always returns Foo.FooValue.X, and never any of the other values as I iterate through the enumeration.
How do I go about mocking the static method multiple times within the single JUnit test? I want to do something like this (but obviously it doesn't work):
public class MyClassTest extends TestCase {
#NonStrict private final Foo mock = null;
#Test public void testMyClass() {
for (final Foo.FooValue val : Foo.FooValue.values() {
new Expectations() {
{
// Here, I'm attempting to redefine the mocked method during each iteration
// of the loop. Apparently, that doesn't work.
Foo.getValue((Object) any); result = val;
}
};
myClass.doSomething();
}
}
}
Any ideas?
Instead of "mocking the method multiple times", you should record multiple consecutive return values in a single recording:
public class MyClassTest extends TestCase
{
#Test
public void testMyClass(#Mocked Foo anyFoo)
{
new Expectations() {{
Foo.getValue(any);
result = Foo.FooValue.values();
}};
for (Foo.FooValue val : Foo.FooValue.values() {
myClass.doSomething();
}
}
}
It could also be done with a Delegate, if more flexibility was required.

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