Rips
Rips

Reputation: 2004

Want spring bean to have mocked as well as real implementations+spring+mockito

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

Answers (4)

Inna
Inna

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

Rips
Rips

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

Vikdor
Vikdor

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

Ammar
Ammar

Reputation: 4024

This can be achieved via @Spy

Your code should look like something below

public class ServiceTest {

    @InjectMocks
    Service service;

    @Mock
    OBject1 obj1;

    @Spy 
    Object obj2 = new SomeObject("argument");

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
    }
}

Upvotes: 0

Related Questions