Mocking the Qualified beans using mockito for a spring-boot application - spring

consider my scenario
public class SomeClass {
#Autowired #Qualifier("converter1") private IConverter converter1;
#Autowired #Qualifier("converter2") private IConverter converter2;
public void doSomeAction(String mimeType) {
converter1.execute();
converter2.execute();
}
}
This is my code.
In order to test this
#RunWith(MockitoJUnitRunner.class)
public class SomeClassTest {
#Mock(name="converter1") IConverter converter1;
#Mock(name="converter2") IConverter converter2;
#InjectMocks SomeClass class = new SomeClass();
#Test
public void testGetListOfExcelConverters() throws Exception {
class.doSomeAction("abcd");
}
}
Here the mocks are not getting injected, please help with the proper mechanism for mocking a qualified beans.
If this is not the right way to code using spring, please let me know the correct method for using this.

Not sure what error you are getting, but your test class doesn't compile because you have what looks like you intend to be a variable name using the keyword class. This worked for me:
#RunWith(MockitoJUnitRunner.class)
public class SomeClassTest {
#Mock(name="converter1") IConverter converter1;
#Mock(name="converter2") IConverter converter2;
#InjectMocks
SomeClass clazz = new SomeClass();
#Test
public void testGetListOfExcelConverters() throws Exception {
clazz.doSomeAction("abcd");
verify(converter1).execute();
verify(converter2).execute();
}
}
And by "worked for me" I mean that the test actually ran and passed. Note I added a couple of verify statements to assert that the injected mocks got called.
I used the SomeClass code you provided as-is.

For me, both existing answers were insufficient.
#riddy 's answer did not take into account different test cases.
#jhericks ' answer did not use the Spring context, which caused other issues down the line.
Here's my solution:
#MockBean
#Qualifier("myNamedBean")
private SomeBean someBean;
As simple as that.

You can mock beans using a test configuration:
#Configuration
public class TestConfig {
#Bean
public MyService myService() {
return Mockito.mock( MyService.class );
}
}

I've found this solution:
#RunWith(MockitoJUnitRunner.class)
public class SomeClassTest {
#Mock()
#Qualifier("converter1")
IConverter converter1;
#Mock()
#Qualifier("converter1")
IConverter converter2;
#InjectMocks SomeClassTest testObj = new SomeClassTest();
#Test
public void testGetListOfExcelConverters() throws Exception {
testObj.doSomeAction("abcd");
verify(converter1).execute();
verify(converter2).execute();
}
}
BTW, I haven't found this in doc.

In my app, the #Autowired beans are passed as constructor args. None of the variations (albeit JUnit 5 version) were working. Instead, I had to "kick it old school" and simply instantiate the mocks directly.
public class SomeClass {
private final IConverter converter1;
private final IConverter converter2;
public SomemClass( #Autowired #Qualifier("converter1") conv1,
#Autowired #Qualifier("converter2") conv2 ) {
this.converter1 = conv1;
this.converter2 = conv2;
}
public void doSomeAction(String mimeType) {
converter1.execute();
converter2.execute();
}
}
public class SomeClassTest {
IConverter converter1;
IConverter converter2;
SomeClass pojo;
#BeforeEach
public void setup() {
converter1 = Mockito.mock( IConverter.class );
converter2 = Mockito.mock( IConverter.class );
pojo = new SomeClass( converter1, converter2 );
}
#Test
public void testGetListOfExcelConverters() throws Exception {
pojo.doSomeAction("abcd");
}
}

Related

How to mock a ObjectProvider<XXX> that is autowired?

I am doing a migration from Spring 4.x to 5.x and am following the recommendation to wrap the object with an ObjectProvider to handle beans that return null: https://stackoverflow.com/a/49393682/10863988
This is the class set up I have:
class ConfigurationClass{
#Autowired
private ObjectProvider<MyObject> myObject;
public SomeOtherClass getSomeOtherClass() {
return new SomeOtherClass(myObject.getIfAvailable());
}
}
class TestSomeOtherClass {
#Mock
MyObject myObject;
#InjectMocks
ConfigurationClass;
SomeOtherClass someOtherClass;
public void setup() {
this.someOtherClass = spy(configuration.getSomeOtherClass());
}
}
The problem is when I run this test. the myObject in the ConfigurationClass returns a null pointer exception.
I've tried adding this to the TestSomeOtherClass but I still can't seem to mock the ObjectProvider<MyObject>:
class TestSomeOtherClass {
#Mock
MyObject myObject;
#Mock
ObjectProvider<MyObject> myObjectObjectProvider;
#InjectMocks
ConfigurationClass;
SomeOtherClass someOtherClass;
public void setup() {
doReturn(myObject).when(myObjectObjectProvider).getIfAvailable();
this.someOtherClass = spy(configuration.getSomeOtherClass());
}
}
Any advice on how to handle this?
You do not tell Mockito to handle it's annotations (#Mock, #InjectMocks) anywhere in your code, so they do not have any effect. By default all non-primitive fields in Java are initialized as null - that's where the NullPointerException comes from.
openMocks/initMocks method
Depending on the version of Mockito you're using, you need to call initMocks() or openMocks() static method from the MockitoAnnotations class:
AutoCloseable openMocks;
#BeforeEach
public void setup() {
// the line below is where the magic happens
openMocks = MockitoAnnotations.openMocks(this);
doReturn(myObject).when(myObjectObjectProvider)
.getIfAvailable();
someOtherClass = spy(configuration.getSomeOtherClass());
}
#AfterEach
void tearDown() throws Exception {
openMocks.close();
}
#Test
void test() {
assertNotNull(someOtherClass);
}
#ExtendWith(MockitoExtension.class)
You can also use the #ExtendWith(MockitoExtension.class) annotation over your class and it has the same effect as the methods described above.
You can find both approaches tested in a GitHub repository I've created (all tests pass).

Verifying pointcuts being called in tests

I have a dummy project where I try figure out how to test pointcuts being triggered.
My project consists of 1 aspect bean which just prints after a foo method is called
#Component
#Aspect
public class SystemArchitecture {
#After("execution(* foo(..))")
public void after() {
System.out.println("#After");
}
}
And a FooServiceImpl with implemented foo method
#Service
public class FooServiceImpl implements FooService{
#Override
public FooDto foo(String msg) {
return new FooDto(msg);
}
}
The code works and and I can see "#After" being printed to console, but I can't check programatically if after pointcut was called using the test below.
#SpringBootTest
public class AspectTest {
#Autowired
private FooService fooService;
#Test
void shouldPass() {
fooService.foo("hello");
}
}
I've also tried using non-bean proxy as was adviced in https://stackoverflow.com/a/56312984/18224588, but this time I'm getting an obvious error cannot extend concrete aspect because my spy proxy is no longer viewed as an aspect:
public class AspectNoContextTest {
#Test
void shouldPass() {
FooService fooService = Mockito.mock(FooService.class);
SystemArchitecture systemArchitecture = Mockito.spy(new SystemArchitecture());
AspectJProxyFactory aspectJProxyFactory = new AspectJProxyFactory(fooService);
aspectJProxyFactory.addAspect(systemArchitecture);
DefaultAopProxyFactory proxyFactory = new DefaultAopProxyFactory();
AopProxy aopProxy = proxyFactory.createAopProxy(aspectJProxyFactory);
FooService proxy = (FooService) aopProxy.getProxy();
proxy.foo("foo");
verify(systemArchitecture, times(1)).after();
}
}
Ok, after some digging, I found that it's possible to accomplish this by making an aspect a #SpyBean. Also AopUtils can be used for performing additional checks
#SpringBootTest
public class AspectTest {
#Autowired
private FooService fooService;
#SpyBean
private SystemArchitecture systemArchitecture;
#Test
void shouldPass() {
assertTrue(AopUtils.isAopProxy(fooService));
assertTrue(AopUtils.isCglibProxy(fooService));
fooService.foo("foo");
verify(systemArchitecture, times(1)).after();
}
}

No primary or default constructor found for Pageable in Pact Contract Provider test

I set up following pact contract provider test
#RunWith(SpringRestPactRunner.class)
#Provider("structures")
#PactFolder("pacts")
#VerificationReports({"console", "markdown"})
#SpringBootTest
public class ContractTest {
#MockBean
private MyServiceImpl myServiceImpl;
#Autowired
private MyController myController;
#Configuration
public static class TestConfiguration {
#Bean
public MyController myController() {
return new MyController();
}
}
#TestTarget
public final MockMvcTarget target = new MockMvcTarget();
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
target.setControllers(myController);
}
#State("My state")
public void setupDocumentWithStructures() {
Mockito.when(myService.getStructuresByDocumentId(
ArgumentMatchers.eq("1"),
ArgumentMatchers.any()
)).thenReturn(new PageImpl<>(Arrays.asList(
Structure.of("first"),
Structure.of("second")
)));
}
}
Running the test results in:
java.lang.AssertionError:
0 - Request processing failed; nested exception is java.lang.IllegalStateException: No primary or default constructor found for interface org.springframework.data.domain.Pageable
java.lang.IllegalStateException: No primary or default constructor found for interface org.springframework.data.domain.Pageable
The method getStructuresByDocumentId expects a Pageable object as its second argument. Changing the annotation #SpringBootTest to
#WebMvcTest(MyController.class)
#EnableSpringDataWebSupport
Doesn't solve the problem. Any ideas, how to solve this issue?
you used "myService" in your setupDocumentWithStructures whereas your #MockBean is myServiceImpl.......I think you meant to use myServiceImpl in setupDocumentWithStructures
That's how it can work
#Before
public void setupOrInit() {
this.mockMvc = MockMvcBuilders.standaloneSetup(controller)
.setControllerAdvice(new ErrorRequestInterceptor(tracer))
.setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
.build();
}
I was having the same problem and fixed setting a new mockMvc like this
#Before
public void before() {
MockitoAnnotations.initMocks(this);
target.setMockMvc(MockMvcBuilders.standaloneSetup(myController)
.setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
.build());
}
I am not using #SpringBootTest as you are, but I think in this case it does not matter. Below is my entire (redacted) code.
#RunWith(SpringRestPactRunner.class)
#Provider("my-provider")
#PactBroker(url = "https://pact-broker.my-compnay.com")
public class MyControllerProviderContractTest {
#TestTarget
public final MockMvcTarget target = new MockMvcTarget();
#Mock
private MyService myService;
#InjectMocks
private MyController myController = new MyController();
#Before
public void before() {
MockitoAnnotations.initMocks(this);
target.setMockMvc(MockMvcBuilders.standaloneSetup(myController)
.setCustomArgumentResolvers(new PageableHandlerMethodArgumentResolver())
.build());
}
#State("my state")
public void stateForMyMethod() {
//my mocks
}
}
I hope this helps, I spend a few hours trying to solve this.
Cheers

Spring boot autowiring an interface with multiple implementations

In normal Spring, when we want to autowire an interface, we define it's implementation in Spring context file.
What about Spring boot?
how can we achieve this?
currently we only autowire classes that are not interfaces.
Another part of this question is about using a class in a Junit class inside a Spring boot project.
If we want to use a CalendarUtil for example, if we autowire CalendarUtil, it will throw a null pointer exception. What can we do in this case? I just initialized using "new" for now...
Use #Qualifier annotation is used to differentiate beans of the same interface
Take look at Spring Boot documentation
Also, to inject all beans of the same interface, just autowire List of interface
(The same way in Spring / Spring Boot / SpringBootTest)
Example below:
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
public interface MyService {
void doWork();
}
#Service
#Qualifier("firstService")
public static class FirstServiceImpl implements MyService {
#Override
public void doWork() {
System.out.println("firstService work");
}
}
#Service
#Qualifier("secondService")
public static class SecondServiceImpl implements MyService {
#Override
public void doWork() {
System.out.println("secondService work");
}
}
#Component
public static class FirstManager {
private final MyService myService;
#Autowired // inject FirstServiceImpl
public FirstManager(#Qualifier("firstService") MyService myService) {
this.myService = myService;
}
#PostConstruct
public void startWork() {
System.out.println("firstManager start work");
myService.doWork();
}
}
#Component
public static class SecondManager {
private final List<MyService> myServices;
#Autowired // inject MyService all implementations
public SecondManager(List<MyService> myServices) {
this.myServices = myServices;
}
#PostConstruct
public void startWork() {
System.out.println("secondManager start work");
myServices.forEach(MyService::doWork);
}
}
}
For the second part of your question, take look at this useful answers first / second
You can also make it work by giving it the name of the implementation.
Eg:
#Autowired
MyService firstService;
#Autowired
MyService secondService;
Assume that you have a GreetingService
public interface GreetingService {
void doGreetings();
}
And you have 2 implementations HelloService
#Service
#Slf4j
public class HelloService implements GreetingService{
#Override
public void doGreetings() {
log.info("Hello world!");
}
}
and HiService
#Slf4j
#Service
public class HiService implements GreetingService{
#Override
public void doGreetings() {
log.info("Hi world!");
}
}
Then you have another interface, which is BusinessService to call some business
public interface BusinessService {
void doGreetings();
}
There are some ways to do that
#1. Use #Autowired
#Component
public class BusinessServiceImpl implements BusinessService{
#Autowired
private GreetingService hiService; // Spring automatically maps the name for you, if you don't want to change it.
#Autowired
private GreetingService helloService;
#Override
public void doGreetings() {
hiService.doGreetings();
helloService.doGreetings();
}
}
In case you need to change your implementation bean name, refer to other answers, by setting the name to your bean, for example #Service("myCustomName") and applying #Qualifier("myCustomName")
#2. You can also use constructor injection
#Component
public class BusinessServiceImpl implements BusinessService {
private final GreetingService hiService;
private final GreetingService helloService;
public BusinessServiceImpl(GreetingService hiService, GreetingService helloService) {
this.hiService = hiService;
this.helloService = helloService;
}
#Override
public void doGreetings() {
hiService.doGreetings();
helloService.doGreetings();
}
}
This can be
public BusinessServiceImpl(#Qualifier("hiService") GreetingService hiService, #Qualifier("helloService") GreetingService helloService)
But I am using Spring Boot 2.6.5 and
public BusinessServiceImpl(GreetingService hiService, GreetingService helloService)
is working fine, since Spring automatically get the names for us.
#3. You can also use Map for this
#Component
#RequiredArgsConstructor
public class BusinessServiceImpl implements BusinessService {
private final Map<String, GreetingService> servicesMap; // Spring automatically get the bean name as key
#Override
public void doGreetings() {
servicesMap.get("hiService").doGreetings();
servicesMap.get("helloService").doGreetings();
}
}
List also works fine if you run all the services. But there is a case that you want to get some specific implementation, you need to define a name for it or something like that. My reference is here
For this one, I use #RequiredArgsConstructor from Lombok.
As mentioned in the comments, by using the #Qualifier annotation, you can distinguish different implementations as described in the docs.
For testing, you can use also do the same. For example:
#RunWith(SpringRunner.class)
#SpringBootTest
public class MyClassTests {
#Autowired
private MyClass testClass;
#MockBean
#Qualifier("default")
private MyImplementation defaultImpl;
#Test
public void givenMultipleImpl_whenAutowiring_thenReturnDefaultImpl() {
// your test here....
}
}
There are 2 approaches when we have autowiring of an interface with multiple implementations:
Spring #Primary annotation
In short it tells to our Spring application whenever we try to autowire our interface to use that specific implementation which is marked with the #Primary annotation. It is like a default autowiring setting. It can be used only once per cluster of implementations of an interface. → #Primary Docs
Spring #Qualifier annotation
This Spring annotation is giving us more control to select the exact implementation wherever we define a reference to our interface choosing among its options. → #Qualifier Docs
For more details follow the links to their documentation.
public interface SomeInterfaces {
void send(String message);
String getType();
}
kafka-service
#Component
public class SomeInterfacesKafkaImpl implements SomeInterfaces {
private final String type = "kafka";
#Override
public void send(String message) {
System.out.println(message + "through Kafka");
}
#Override
public String getType() {
return this.type;
}
}
redis-service
#Component
public class SomeInterfacesRedisImpl implements SomeInterfaces {
private final String type = "redis";
#Override
public void send(String message) {
System.out.println(message + "through Redis");
}
#Override
public String getType() {
return this.type;
}
}
master
#Component
public class SomeInterfacesMaster {
private final Set<SomeInterfaces> someInterfaces;
public SomeInterfacesMaster(Set<SomeInterfaces> someInterfaces) {
this.someInterfaces = someInterfaces;
}
public void sendMaster(String type){
Optional<SomeInterfaces> service =
someInterfaces
.stream()
.filter(service ->
service.getType().equals(type)
)
.findFirst();
SomeInterfaces someService =
service
.orElseThrow(() -> new RuntimeException("There is not such way for sending messages."));
someService .send(" Hello. It is a letter to ....");
}
}
test
#SpringBootTest
public class MultiImplementation {
}
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
class SomeInterfacesMasterTest extends MultiImplementation {
#Autowired
private SomeInterfacesMaster someInterfacesMaster;
#Test
void sendMaster() {
someInterfacesMaster.sendMaster("kafka");
}
}
Thus, according to the Open/Closed principle, we only need to add an implementation without breaking existing code.
#Component
public class SomeInterfacesRabbitImpl implements SomeInterfaces {
private final String type = "rabbit";
#Override
public void send(String message) {
System.out.println(message + "through Rabbit");
}
#Override
public String getType() {
return this.type;
}
}
test-v2
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
class SomeInterfacesMasterTestV2 extends MultiImplementation {
#Autowired
private SomeInterfacesMaster someInterfacesMaster;
#Test
void sendMasterV2() {
someInterfacesMaster.sendMaster("rabbit");
}
}
If we have multiple implementations of the same interface, Spring needs to know which one it should be autowired into a class. Here is a simple example of validator for mobile number and email address of Employee:-
Employee Class:
public class Employee {
private String mobileNumber;
private String emailAddress;
...
/** Getters & Setters omitted **/
}
Interface EmployeeValidator:
public interface EmployeeValidator {
public Employee validate(Employee employee);
}
First implementation class for Mobile Number Validator:
#Component(value="EmployeeMobileValidator")
public class EmployeeMobileValidator implements EmployeeValidator {
#Override
public Employee validate(Employee employee) {
//Mobile number Validation logic goes here.
}
}
Second implementation class for Email address Validator:
#Component(value="EmployeeEmailValidator")
public class EmployeeEmailValidator implements EmployeeValidator {
#Override
public Employee validate(Employee employee) {
//Email address validation logic goes here.
}
}
We can now autowired these above validators individually into a class.
Employee Service Interface:
public interface EmployeeService {
public void handleEmployee(Employee employee);
}
Employee Service Implementation Class
#Service
public class EmployeeServiceImpl implements EmployeeService {
/** Autowire validators individually **/
#Autowired
#Qualifier("EmployeeMobileValidator") // Autowired using qualifier for mobile validator
private EmployeeValidator mobileValidator;
#Autowired
#Qualifier("EmployeeEmailValidator") // Autowired using qualifier for email valodator
private EmployeeValidator emailValidator;
#Override
public void handleEmployee(Employee employee) {
/**You can use just one instance if you need**/
employee = mobileValidator.validate(employee);
}
}

Mock an object which is part of mocked object

when I run the test case I get AnObj mocked. this is used from inside the target classes method. when that method gets invoked the 'anOtherObj' is accessed and that is found to be null. Can some one please point out how to make sure 'anOtherObj' is not null so that I dont get nullpointer there?
#Test
public class TestTargetTest {
#Mock
private AnObj anObj;
#InjectMocks
private TestTarget testTarget;
#BeforeMethod
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void testTarget() {
when(anObj.someMethod()).thenCallRealMethod();
testTarget.testTarget();
}
}
#Component
public class TestTarget {
#Autowired
private AnObj anObj;
public void testTarget(){
anObj.someMethod();
}
}
#Component
public class AnObj {
#Autowired
private AnOtherObj anOtherObj;
public void someMethod(){
syso(anOtherObj.toString());
}
}
You need to initialize annotated mocks in your test class.
#BeforeMethod
public void beforeClass() {
MockitoAnnotations.initMocks(this);
}
Why would you care what's inside mock (AnObj)? I assume you haven't yet declared interactions on that mock using Mockito.when.
As mentioned by #Valya that point was valid. I shouldn't have mocked that. I needed to autowire 'AnObj'. Thanks a lot for all the help. It made the difference.

Resources