#RunWith(SpringRunner.class) vs #RunWith(MockitoJUnitRunner.class) - junit

I was using #RunWith(MockitoJUnitRunner.class) for my junit test with mockito. But now i am working with spring boot app and trying to use #RunWith(SpringRunner.class) . Does using #RunWith(SpringRunner.class) has any advantages over using #RunWith(MockitoJUnitRunner.class)? Can i still use feature like #Injectmock, #Mock, #Spy with #RunWith(SpringRunner.class)

The SpringRunner provides support for loading a Spring ApplicationContext and having beans #Autowired into your test instance. It actually does a whole lot more than that (covered in the Spring Reference Manual), but that's the basic idea.
Whereas, the MockitoJUnitRunner provides support for creating mocks and spies with Mockito.
However, with JUnit 4, you can only use one Runner at a time.
Thus, if you want to use support from Spring and Mockito simultaneously, you can only pick one of those runners.
But you're in luck since both Spring and Mockito provide rules in addition to runners.
For example, you can use the Spring runner with the Mockito rule as follows.
#RunWith(SpringRunner.class)
#SpringBootTest
public class MyTests {
#Rule
public MockitoRule rule = MockitoJUnit.rule();
#Mock
MyService myService;
// ...
}
Though, 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.

When SpringRunner.class is used, Spring provides corresponding annotations:
#MockBean
#SpyBean
Mocks are injected to objects under tests via #Autowired annotation. To enable this functionality tests must be annotated with
#SpringBootTest
or
#TestExecutionListeners(MockitoTestExecutionListener.class)
More details and examples can be found in the official documentation: Mocking and Spying Beans

As per the JavaDoc:
SpringRunner is an alias for the SpringJUnit4ClassRunner.
To use this class, simply annotate a JUnit 4 based test class with #RunWith(SpringRunner.class).
If you would like to use the Spring TestContext Framework with a runner other than this one, use org.springframework.test.context.junit4.rules.SpringClassRule and org.springframework.test.context.junit4.rules.SpringMethodRule.
And the JavaDoc of TestContext:
TestContext encapsulates the context in which a test is executed, agnostic of the actual testing framework in use.
That of method getApplicationContext():
Get the application context for this test context, possibly cached.
Implementations of this method are responsible for loading the application context if the corresponding context has not already been loaded, potentially caching the context as well.
So, SpringRunner does load the context and is responsible for maintaining it. For example, if you want to persist data into an embedded database, like H2 in-memory database, you have to use SpringRunner.class; and, to clean the tables to get rid of the records you inserted after every test, you annotate the test with #DirtiesContext to tell Spring to clean it.
But, this is already an integration or component test. If your test is pure unit test, you don't have to load DB, or you just want to verify some method of a dependency is called, MockitoJUnit4Runner suffices. You just use #Mock as you like and Mockito.verify(...) and the test will pass. And it is a lot quicker.
Test should be fast. As fast as possible. So whenever possible, use MockitoJUnit4Runner to speed it up.

Scenario 2019 November : spring-boot : 2.1.1.RELEASE
You have a spring boot api rest
You need to test a service called MySuperSpringService
But, inside MySuperSpringService, are required two more autowires. One to perform a sql select (MyJpaRepository) and another to call an external api rest (MyExternalApiRest)
#Service
public class MySuperSpringService {
#Autowired
private MyRepository innerComponent1;
#Autowired
private MyExternalApiRest innerComponent2;
public SomeResponse doSomething(){}
}
How test MySuperSpringService mocking database and external api rest ?
So, in order to test this service MySuperSpringService which needs another spring beans: MyJpaRepository and MyExternalApiRest, you need to mock them using #MockBean and create the result as you need.
import static org.mockito.Mockito.when;
import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.junit4.SpringRunner;
import junit.framework.TestCase;
#RunWith(SpringRunner.class)
#SpringBootTest(classes = your.package.Application.class)
public class MySuperSpringServiceTest extends TestCase {
#Autowired
private MySuperSpringService serviceToTest;
#MockBean
private MyRepository myRepository;
#MockBean
private MyExternalApiRest myExternalApiRest;
#Before
public void setUp() {
Object myRepositoryResult = new Object();
//populate myRepositoryResult as you need
when(myRepository.findByClientId("test.apps.googleusercontent.com"))
.thenReturn(myRepositoryResult);
Object myExternalApiRestResult = new Object();
//populate myExternalApiRestResult as you need
when(myExternalApiRest.listUserRoles("john#doe.com")).thenReturn(myExternalApiRestResult);
}
#Test
public void testGenerateTokenByGrantTypeNoDatabaseNoGoogleNoSecurityV1(){
SomeResponse response = serviceToTest.doSomething();
//put your asserts here
}
}

you can absolutely use SpringRunner for both unit tests and integration tests.
SpringRunner Tutorial

Related

Mock a particular method in DAO layer in junit

I have an application with rest api endpoints. I want to write test cases for that. It follows MVC architecture. For one of the end points I want to mock a method in my DAO class.
Sample code for my test class is:
RequestBuilder requestGetBuilder = MockMvcRequestBuilders
.get("/processcal/getdata/srn/{srn}",1000)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON);
This controller will call the DAO layer having that method to be mocked.
I tried using the mockito as below in my Test config class:
#Bean
#Primary
BookMarkDao bookMarkDao() {
final BookMarkDao bookMarkDao = Mockito.mock(BookMarkDao.class);
Mockito.when(bookMarkDao.fetchMrPostProcessCalc(Mockito.anyString()))
.thenReturn(TestUtils.getMockResponse());
return bookMarkDao;
}
The problem with this is it's mocking the entire DAO bean so for rest of the endpoints its not calling the DAO class methods and my test coverage reduces. Is there a way around solving this?
You can use a specific profile for mocked beans and activate this profile in necessary test cases. By the way, if your application based on the spring-boot then you can use #MockBean instead of manual making a mock of your DAO in test configurations.

Mock Service into Service with Mockito and JUNIT and CDI

I have 3 services
class Service1{
#Inject private Service2 service2;
}
class Service2{
#Inject private Service3 service3;
}
class Service3{
public Object test(){
...}
}
class TestService1{
//do a test and mock the method in service3
when(service3.test()).doReturn(Something());
}
I have to mock the method in service 3 injected in service 2 which is injected in service 1
any idea? I have to test it directly like that I have no other way to do it.
As the last service is a call to a rest Service, i created an interface IServiceC then 2 implementations of it, one in the main/src/java, another in test/src/java and all services are returned hardcoded values. because the complexity here is to say ok i will inject all service but not the last, and tell to second layer i inject you but i mock you too etc...
very too complicated to manage, with a mock class implementation i don't have to cary about this topic, i use arquillian and all will be injected (i exclude from the war package the default implementation and add the mock implementation to the war)

In junit how to mock literay multivmpoolutil.class?

In my portlet, I'm using MultiVMPoolUtil.getPortalcache("test")
This portet needs to be tested.. For this Mockito
Mock.. Try to set portalcache using mock of above class..
But mock the above class is not running in junit
... When we mock MultiVMPoolUtil
The mockito junit test states that .. Cannot able to mock the liferay
MultiVMpoolutil.class
#Mock
private MultiVmpoolutil
#Before
public void setup()
How to mock this class.. Is there any other way to slove this?
Static classes can be mocked with PowerMock. It´s also my last sword for fighting against util classes. furthermore it also allows very deep manipulation opportunities, like suppressing constructors of super classes or even static initializers (helpful when mocking the PropsUtil).
https://github.com/powermock/powermock
https://github.com/powermock/powermock/wiki/Suppress-Unwanted-Behavior

How to use values from porperty files in a global context with Junit5 and CitrusExtension

Maybe I'm on the wrong course or totally misunderstanding something.
I've merged a Citrus IntegrationTest from Junit4Runner to Junit5 (with CitrusExtension).
There is an EndpointConfiguration class
#Configuration
#PropertySource("test-setup.properties")
#PropertySource("service-paths.properties")
public class RestEndpointConfig {
#Value("${testenv.host}") //defined in test-setup.properties
private String host;
...
}
And a TestClass
#ExtendWith(CitrusExtension.class)
#RunWith(JUnitPlatform.class)
public class BaseIT{
#CitrusEndpoint
protected HttpClient httpClient;
#Value("${rest.session}") //defined in service-paths.properties
private String sessionPath;
}
In the test class I want to access values defined in the service-paths.properties file.
This worked with JUnit4 but after the changes to JUnit5 it seems that the properties are no longer available in a 'global' context.
Turning the log level to 'debug' shows, that the properties file is loaded.
So my question is: What do I need to change in order to get access to the service-paths properies in my IT classes. What am I missing, what is best practice in this case?
Thanks in advance for any feedback.
Property value resolving via #Value annotation is a core Spring framework feature. So you need to add SpringExtension to your JUnit5 test. You can do this in addition to using the CitrusExtension.

Deep / Nested Dependency Injection in testing

I am using junit, mockito and mockMVC to test the working of a webapp. I am struggling with a dependency whose injecttion I cannot figure out. My webapp structure is as follows.
Class Controller{
#Autowired Service searchService;
#RequestMapping("Search")
public returnType search(#RequestParam("parameter")String parameter){
searchService.doSearch(parameter);
}
}
and the service class
Class Service{
#Autowired Service2 service2;
public returnType doSearch(String parameter){
//some code
service2.call(parameter);
}
}
I need to test the search method for this controller, however service2 is not currently live and hence calls to it have to be mocked. I can mock service2, but cannot figure out how to inject a mock of service2 in my mockMVC instance of controller. As far as I know #InjectMocks in mockito only injects mocks one level deep and not two.
EDIT:
I am using the following to get MockMVC instance of controller
MockMvc controller;
controller = MockMvcBuilders.standaloneSetup(Controller);
What you are essentially want to do is mock a bean.
In your case, you have to mock bean for service2 using #MockBean annotations.
Please refer this article for details.
You don't need that.
Mocking search service will be sufficient as you get the handle of what needs to be done.
Example:
doReturn(...).when(searchService).doSearch(any());
While performing Unit Testing, the developer need to identify the System Under Test and mock/stub all the collaborators.
So, in this case you would write a separate unit test for Controller and Search Service.
Also, read this brilliant article by Martin Fowler - Mocks Aren't Stubs.