Reputation: 2004
I have a class Service
which I want to test. Basically, I am facing an issue as I want Service
object to be partially mocked. Only obj1
should be mocked and the rest of the other collaborators should be real ones. My code is similar to this:
@Component
public class Service {
@Autowired
Object1 obj1;
@Autowired
Object2 obj2;
public void validate(){
obj1.isValid();
obj2.isActive();
}
}
Now while testing validate method of the above Service
class, I want to mock the obj1.isValid()
method while invoking real implementation of obj2
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:conf/test-context.xml"})
public class ServiceTest {
@InjectMocks
Service service;
@Mock
OBject1 obj1;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
public void testValidate (){
service.validate();
//assert and other stuff
}
}
This test fails and when I debugged validate method, I found that obj1
instance is injected as mocked as expected in the Service
class but obj2
is injected as null
. Hence the test fails...
Is there any way to achieve this ?
update As I read in some SO answers I used springockito. I added below thing into the test class as below but still same result:
@ReplaceWithMock
@Autowired
Object2 obj2
Upvotes: 0
Views: 161
Reputation: 77
Don't use Autowired and InjectMocks. It's bad practise. You can use both @InjectMocks and @Spy to mock real object and to allow mocking inside this spy object
Upvotes: 0
Reputation: 2004
Another way to achieve this is using springocito.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = SpringockitoContextLoader.class,locations={"classpath:conf/test-context.xml"})
public class ServiceTest
{
@ReplaceWithMock
@Autowired
private Object1 object1
@Autowired
private Service service;
@Before
public void setup()
{
MockitoAnnotations.initMocks(this);
}
@Test
public void test()
{
//assert stuff
}
}
Service will get properly populated except Object1 which will be having mocked instance.Rest of all autowired inner beans will be populated.
Upvotes: 0
Reputation: 24124
You have to add the @Autowired
annotation to service
object so that all other attributes in service
are injected normally and mocked objects are injected for mocked types.
In the example below, normal bean of Class2
will be injected in service
, but the @InjectMocks
annotation will inject the mocked object of Class1
.
Service:
@Component
public class Service
{
@Autowired
private Class1 class1;
@Autowired
private Class2 class2;
public Class1 getClass1()
{
return class1;
}
public Class2 getClass2()
{
return class2;
}
}
Class1:
@Component
public class Class1
{
public String getName()
{
return "Class1";
}
}
Class2:
@Component
public class Class2
{
public String getName()
{
return "Class2";
}
}
Test:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({
"classpath:application-context.xml"
})
public class ServiceTest
{
@Mock
private final Class1 class1 = Mockito.mock(Class1.class);
@InjectMocks
@Autowired
private Service service;
@Before
public void setup()
{
MockitoAnnotations.initMocks(this);
}
@Test
public void test()
{
Mockito.when(class1.getName()).thenReturn("MockClass1");
Assert.assertNotNull(service);
Assert.assertEquals("MockClass1", service.getClass1().getName());
Assert.assertNotNull("Class2", service.getClass2().getName());
}
}
Upvotes: 2