Reputation: 571
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?
Upvotes: 2
Views: 4336
Reputation: 16390
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);
}
Upvotes: 1
Reputation: 7406
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!
Upvotes: 1
Reputation: 140494
(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);
Upvotes: 2