Reputation: 153
Question (in short) - how do I mock a spring dependency that is not directly referenced in my JUnit.
Below is the setup that am working with. ServiceA is an interface and its implementation requires a handful of autowired dependencies for its many logic to work.
public interface ServiceA{
void invoke();
...10 more methods
}
@Service
public class ServiceAImpl implements ServiceA{
@Autowired
private ServiceB serviceB;
@Autowired
private ServiceC serviceC;
@Autowired
private DAOA daoA;
@Autowired
private DAOB daoB;
@Override
public void invoke(arg1, arg2){
// use above dependencies to do something
serviceB.sendEmail(args);
}
}
ServiceB sends an email by invoking yet another util dependency.
public interface ServiceB{
void sendEmail();
...10 more methods
}
@Service
public class ServiceBImpl implements ServiceB{
@Autowired
private EmailUtil emailUtil;
@Override
public void sendEmail(args){
emailUtil.sendEmail(args);
}
Its worth noting that the sendEmail method returns void.
@Component
publIt'sclass EmailUtil{
@Autowired
private JavaMailSenderImpl javaMailSenderImpl;
public void sendEmail(args){
// send email using spring & other APIs
}
}
My integration test JUnit looks like this.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/test-context.xml" })
public class ServiceIT{
@Autowired
private ServiceA serviceA;
@Test
public void testA(){
// prepare data mock in H2 DB
serviceA.invoke(arg1, arg2);
// assertions
}
}
Question (long) - Am using H2 as mock DB so my DAO calls can (need to) function. I want to mock other 3rd party integrations, such as emailUtil.sendEmail call in serviceB so that email is not sent. Since in my JUnit am using serviceA, my understanding is that, I need to create @Mock of EmailUtil and @InjectMocks it into ServiceB which is @InjectMocks into ServiceA. When I do this, Mockito throws errors saying ServiceB is an interface. Creating mock objects of ServiceA, ServiceB may not be a great option, because then I might have to stub/mock too many behaviors. I want the actual logic to be executed in these classes, the mocking should be done only for sendEmail method.
Spring - 4.0.3.RELEASE, JUnit - 4.12, mockito-core - 1.10.19
Upvotes: 1
Views: 2898
Reputation: 40058
In the test class ServiceIT
mock EmailUtil
using @MockBean
Annotation that can be used to add mocks to a Spring ApplicationContext. Can be used as a class level annotation or on fields in either @Configuration classes, or test classes that are @RunWith the SpringRunner.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/test-context.xml" })
public class ServiceIT{
@Autowired
private ServiceA serviceA;
@MockBean
private EmailUtil emailUtil;
@Test
public void testA(){
// prepare data mock in H2 DB
//given(this.emailUtil.sendEmail(ArgumentMatchers.any()).willReturn( custom object);
serviceA.invoke(arg1, arg2);
// assertions
}
}
Upvotes: 0