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.
Related
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.
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);
}
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.
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
In JUnit / Mockito we have 2 extremly useful annotations: #Mock and #InjectMocks.
In my new project i started using groovy with spock for testing, I'm wondering if there is a replacement for mentioned annotations?
There is no real need for #Mock in Spock, because there is already = Mock(), which can be used everywhere an annotation can be used (and also in other places). There is an open pull request for #InjectMocks, but it hasn't been decided if such a feature will make it into spock-core or spock-guice. (Shipping this feature with spock-guice, or at least requiring Guice on the class path, would allow to delegate injection to Guice, rather than reinventing the wheel.) If not, #InjectMocks could always be shipped as a third-party Spock extension.
Someone wrote an annotation two months ago: https://github.com/msid256/MockInjector4Spock.
The bean you want to test doesn't need to be instantiated manually. All you need to do is to declare it as a field and annotate it with #InjectMocks.
#Service
class ServiceC {
#Autowired
public ServiceC(ServiceA a, ServiceB b) {}
}
class DemoSpec extends Specification {
#Autowired
ServiceA serviceA;
ServiceB serviceB = Mock(ServiceB.class)
#InjectMocks // from MockInjector4Spock - de.github.spock.ext.annotation.InjectMocks
ServiceC serviceC;
}
https://github.com/marcingrzejszczak/spock-subjects-collaborators-extension
you can use #Collaborator and #Subject instead #Mock and #InjectMocks
In groovy there is no private scope, so we can modify the members of the class under test directly. So we can assign the member to our mocked value.