Micronaut with MockitoTests - java

I have a requirement to test my service layer in Micronaut.
I am using bean validation in my service layer and so I need validator to be injected in the testing phase and I can't just mock it. However, I want to mock some other classes and so I am also using Mockito as well.
The problem is if I am putting #MicornautTest on my class all the beans marked with #Inject are Not-Null which means that #Inject is working fine. However, as soon as I add #ExtendWith(MockitoExtension.class) to the class and re-run the tests, all the means marked with #Inject are now null and all the beans marked with #Mock are Not-Null.
So it looks like either I can use #Inject in my tests or I can use #Mock but not both.
#MicronautTest
#ExtendWith(MockitoExtension.class)
class CashServiceTest {
#Inject
private Validator validator;
#Mock
private AvailableCashClient availableCashClient;
Has anyone faced similar issue earlier? Can you please guide me the correct configuration which will allow me to use both #Inject and #Mock in the same tests.

I was able to find the issue and was able to use both mocked beans and original injected beans.
The issue is we should not use #ExtendWith annotation and can achieve everything just by using #micronaut test.
I am pasting code for the set up which I did. In this case, BusinessClient is the bean which is being mocked and Validator is the bean which is injected without being mocked.
#MicronautTest
class CashServiceTest {
#Inject
AvailableCashClient availableCashClient;
#Inject
Validator validator;
#MockBean(AvailableCashClient)
public AvailableCashClient availableCashClient() {
return Mockito.mock(AvailableCashClient);
}

Related

When to use and not use #Mock annotation, #MockBean annotation, #InjectMock annotation & #Autowired annotation in a spring webflux reactive project

Can you please explain when to use below annotations and when not to use those. I am pretty new to testing frameworks and confused with all the answers in the web.
#Mock
private Resource resource;
#MockBean
private Resource resource;
#InjectMock
private ProductService productService;
#AutoWired
Private ProductRepository productRepo;
#Mock
Used to make Mockito create a mock object.
#InjectMock
When you want Mockito to create an instance of an object and use the mocks annotated with #Mock as its dependencies.
#AutoWired
Used when you want to autowire a bean from the spring context, works exactly the same as in normal code but can only be used in tests that actually creates an application context, such as tests annotated with #WebMvcTest or #SpringBootTest.
#MockBean
Can be used to add mock objects to the Spring application context. The mock will replace any existing bean of the same type in the application context. If no bean of the same type is defined, a new one will be added. Often used together with #SpringBootTest
So normally you either:
Use #Mock and #InjectMocks for running tests without a spring
context, this is preferred as it's much faster.
Use #SpringBootTest or #SpringMvcTest to start a spring context together with #MockBean to create mock objects and #Autowired to get an instance of class you want to test, the mockeans will be used for its autowired dependencies. You use this when writing integration tests for code that interact with a database or want to test your REST API.

Using SpringRunner with #Mock

I have read that when using #Mock, it should be used with #RunWith(MockitoJUnitRunner.class), while for #MockBean, it uses with #RunWith(SpringRunner.class).
However, for #Mock, I see that both MockitoJunitRunner or SpringRunner can be used interchangeably. I am rather confused as to why SpringRunner is also working in this situation ?
#RunWith(MockitoJUnitRunner.class) // also work when #RunWith(SpringRunner.class) is used
public class testService {
#InjectMocks
private ServiceA serviceA;
#Mock
private DependencyA dependencyA;
}
to quote this thread when talking about #MockBean
the class is included in the spring-boot-test library. It allows to add Mockito mocks in a Spring ApplicationContext.
Basically #MockBean is the combination of an #Mock and a #InjectMocks. Therefore, you could also use #Mock with springrunner but ofcourse it is not recommended because it is more heavy weight.
Generally you would use Mockito for lightweight unit tests, whereas using #MockBean when you want a mocked servlet environment like in a component test or a hybrid integration test.
Difference between #Mock, #MockBean and Mockito.mock()
typically, if you're using Spring Boot and need to mock a bean from the Spring ApplicationContext you would then use Spring Boot's #MockBean support instead of simply #Mock.
If your bean Injection happening via Autowired annotation, then #mock will not work.

Using Mockito is necessary to overwrite all methods?

Using it to test in Spring.
Using #Mock Mockito is necessary to overwrite all methods replies of the original class with when clauses? And what is the difference with #MockBean ?
Its not accessory to override overwrite all methods.
#Mock is pure Mockito library where #MockBean is spring implementation of Mockito
So in your spring component class if not defined #Autowired fields (Just like simple java class to mock as object) then use #Mock annotation to mock the object of that class.
But your sping component class has #Autowired fields and you want spring container initialize that fields as Mock object then use #MockBean annotation (spring will do mock and autowire it).
For ex
class Test {
public void testMethod(){ -- some code --}
}
The you can use #Mock annotation for Test call to mock it. There is no other dependencies or fields in Test class.
#Component
class Test {
#Autowired
Other other;
public void testMethod(){ -- some code --};
}
Then you can mock Other object using #MockBean if you want to mock it and pass by the functionality of other (i.e we mock DAO layer and not calling actual logic). Spring container will initialize that other field.

Mockito: How to mock field dependencies partially in spring bean

I have a Spring service with multiple field dependencies as below. One of the dependency (thirdPartyService) communicates with an external application. How can I just mock that?
#Service
public class PlannerServiceImpl implements PlannerService {
private static final Logger LOG = LoggerFactory.getLogger(PlannerServiceImpl.class);
#Autowired
private RepositoryA repositoryA;
#Autowired
private RepositoryB repositoryB;
#Autowired
private ThirdPartyService thirdPartyService ;
}
If I use Mock annotation then it still connects to external application instead of returning mock response:
#Mock
ThirdPartyService thirdPartyService;
#Autowired
PlannerService plannerService;
And If I use InjectMocks annotation then it gives NullpointerException for RepositoryA and RepositoryB.
#Mock
ThirdPartyService thirdPartyService;
#InjectMocks
PlannerService plannerService = newPlannerService();
How can I just Mock ThirdPartyService and let Spring inject other dependencies?
You can modify what Spring has injected using Whitebox. Optionally, since you are using Spring, you can also use ReflectionTestUtils.setField
After Spring injects the dependencies, and before your unit test runs, you can use org.powermock.reflect.Whitebox to modify Spring's injection. Something like this
Whitebox.setInternalState(plannerService, "thirdPartyService" thirdPartyService);
Where thirdPartyService is your mocked instance.
javadoc here
or using Spring's ReflectionTestUtils:
ReflectionTestUtils.setField((plannerService, "thirdPartyService" thirdPartyService);
java doc here
This can typically be done in your "setup" method, the one annotated with #Before.
You can have a setter method in your PlannerService class under test
void setRepositoryA(RepositoryA repository) {
this.repositoryA = repository;
}
And then use this method in your test to supply a mock implementation of the RepositoryA
Or you can #Inject the repository in the constructor and then in your unit test call the constructor with the mocks as the arguments, instead.
The #Autowiring and #InejctMocks can be used in a test case for sure (annotations being used separately on different instance fields).
Make sure you:
1) Initiate Mockito mocks in the #Before method:
#Before
public void before(){
MockitoAnnotations.initMocks(this);
}
2) Use SpringJUnit4ClassRunner.class in the #RunWith class annotation

Spring / Mock components that are retrieved by using the context directly

We have a project that uses Spring annotations to configure its context.
To test this project we are using Mockito and it's Spring extension.
In tests I need to override some beans with mock/spy version.
With the #Mock/#Spy and #InjectMock annotations I have been able to use spy for beans using autowiring mechanism.
Now I have a third party component which create another Spring context and then merge the 2 contexts together. This third party component retrieve beans using a call to the context:
applicationContext.getBean(key);
In this case, the #Mock/#Spy and #InjectMock combination is not working.
The 'workaround' solution I have put in place is an XML file in which I declare my spied bean:
<mockito:spy beanName="beanToSpy"/>
To stay in the annotation world, I have tried springockito-annotations as mentioned in these similar questions:
Injecting Mockito mocks into a Spring bean
and its duplicate:
How to inject a Mock in a Spring Context
But the bean is not spied or mocked, I've probably a configuration error.
My current setup is:
A base class that is in charge of the Spring config for test:
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles("test")
#ContextConfiguration(loader= SpringockitoContextLoader.class, locations ={"/config.xml","/test-config.xml"})
public abstract class BaseTest {
//...
}
A test class that would like to use a mocked bean:
public class MyTest extends BaseTest {
#ReplaceWithMock #Autowired MyService myService;
#WrapWithSpy #Autowired OtherService otherService;
#Test public void someTest() {
doReturn(x).when(myService).call();
doReturn(y).when(otherService).process();
}
}
Unfortunately in MyTest, the beans are not replaced by their mock/spy versions, it is the plain old regular version.
EDIT:
The third party component that does the lookup is using its own spring parent context and add the current spring context into its own. The lookup to retrieve the component that I want to be mocked occurs after the context has been fully loaded.
What should I do to properly replace the bean in the context with a mock/spy version ?
What is wrong with the way I'm using #WrapWithSpy / #ReplaceWithMock ?
When does the call to
applicationContext.getBean(key);
happens? Is it possible that it retrieves the bean before the SpringockitoContextLoader has a chance to replace it with a spy?
One solution to stay in annotation world would be to override the bean in java config:
#Bean
public MyBeanType myBeanType() {
return spy(new MyBeanType(...))
}
The more conventional way to perform this is by simply mocking them in the test as required :
public class MyTest extends BaseTest {
#Test public void someTest() {
MyService myMockService = Mockito.mock(MyService.class);
// define when's
// perform verification
}
You can inject using SpringReflectionTestUtils, or if using setter injection just set normally.
If you use a global mocked bean in a test class with multiple tests, the results can get confusing.

Categories