Mocking a service in Spring 5.0.7.RELEASE - java

I have a Spring 5.0.7.RELEASE app, with some WebLayer tests I have this test in my app:
#RunWith(SpringRunner.class)
#WebAppConfiguration
public class HongoControllerTest {
#Mock
FactureService factureService;
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
ObjectMapper obj = new ObjectMapper();
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac)
.build();
when(factureService.setLockFilter(any())).thenReturn(Boolean.TRUE);
}
}
but when I run the test, the FactureService is not mocked

I'm not totally sure because you didn't show an actual test but I guess you should use #MockBean and not #Mock.
#Mock is used for plain Unit Test when you do the dependency injection yourself.
#MockBean is used for integration tests when you want to use your Mock as a regular Bean.
Long story shot. Try this:
#MockBean
FactureService factureService;
For more information have a look on this article.

Related

How to enforce MockitoJUnitRunner fail without basic http authentication?

I write a Spring Boot app and I was able to access and test Controller with MockMvc. The issue is that during testing security is not enforced and I can access Controller with no user.
Am I doing anything wrong? Is it intended behavior?
ControllerTest class:
#RunWith(MockitoJUnitRunner.class)
public class ControllerTest {
private MockMvc mockMvc;
#Mock
private Service service;
#InjectMocks
private Controller controller;
private final static String URL = "/test";
#Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
#Test
public void test() throws Exception {
mockMvc.perform(get(URL))
.andExpect(status().isOk());
}
}
My SecurityConfig StackOverflow QA.
Your examples uses a plain unit test to test your controller. In this setup the Controller is created by Mockito (the controller field is annotated with Mockito's #InjectMocks).
Mockito is not aware of Spring, in consequence no Spring Security will be setup in your test.
You need to use the SpringRunner to run your test. This runner is Spring aware and allows you to properly initialize your controller before the test is run.
The test should look something like this (junit5):
#ExtendWith(SpringExtension.class)
#WebMvcTest(controllers = Controller.class)
public class ControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private Service serviceMock;
#Test
public void test() throws Exception {
mockMvc.perform(get(URL))
.andExpect(status().isOk());
}
}
check our the Spring documentation or some tutorials for further information
https://spring.io/guides/gs/testing-web/
https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html

integration test with SpringBoot with both MockMvc and PowerMock on static methods

Can someone provide any sample on this scenario combination. I gave a sample snippet on the lines below, which is failing while trying to mock, intent is to combine both MockMVC with PowerMock
Create a spring Boot Test App for integration testing with
1) MockMvc for initiating a call from controller till end
2) PowerMock to Mock static methods in dependent class
#RunWith(SpringRunner.class)
#PowerMockRunnerDelegate(PowerMockRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
#PrepareForTest(ClasswithStaticMethod.class)
public class DevLocationTest {
#Autowired
private MockMvc mockMvc;
#MockBean
ABCRepository abcRepository;
#MockBean
private ClasswithStaticMethod instance;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void test() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization","");
PowerMockito
.when(abcRepository
.findByDevIdAndPropertyEventNameIn(devId,
Arrays.asList(eventName)))
.thenReturn(devPropMapping);
PowerMockito.mockStatic(ClasswithStaticMethod.class);
Mockito.when(ClasswithStaticMethod.getInstance())
.thenReturn(instance);
which is failing while trying to mock "ClasswithStaticMethod" with error like below, even though i have given #PrepareForTest(ClasswithStaticMethod.class)
The class com.XXX.services.config.ClasswithStaticMethod not prepared for test.
To prepare this class, add class to the '#PrepareForTest' annotation.

Is it good practice to use SpringRunner without SpringContext when writing JUnit test cases?

I tried junit with mockito, and wrote some test cases for a coding exercise.
Here is the test case which i wrote:
#RunWith(SpringRunner.class)
public class TransactionControllerTest {
#Mock
TransactionService transactionServiceMock;
#InjectMocks
TransactionController transactionController;
TransactionRequest txn = new TransactionRequest("123.34", "2018-11-28T23:32:36.312Z");
#Test
public void testSaveTxn() throws Exception {
Mockito.when(transactionServiceMock.saveTxn(Mockito.any(TransactionRequest.class))).thenReturn(true);
ResponseEntity<?> responseEntity = transactionController.saveTxn(null, txn);
assertTrue(responseEntity.getStatusCode().equals(HttpStatus.CREATED));
}
#Test
public void testGetStats() throws Exception {
StatsResponse sr = new StatsResponse("0.00", "0.00", "0.00", "0.00", 0L);
Mockito.when(transactionServiceMock.getStats()).thenReturn(sr);
ResponseEntity<StatsResponse> responseEntity = (ResponseEntity<StatsResponse>) transactionController.getStats(null);
System.out.println("sr response = "+responseEntity.getBody());
assertTrue(responseEntity.getBody().equals(sr));
}
#Test
public void testDelete() throws Exception {
Mockito.doNothing().when(transactionServiceMock).delete();
ResponseEntity<HttpStatus> responseEntity = (ResponseEntity<HttpStatus>) transactionController.deleteTxn(null);
System.out.println("sr response = "+responseEntity.getBody());
assertTrue(responseEntity.getStatusCode().equals(HttpStatus.NO_CONTENT));
}
}
The test cases were working fine.
But my application was rejected specifying the following reason:
You were using SpringRunner even though you are not using SpringContext in the tests, and mocking everything.
Now, following are my concerns:
What's wrong with the test cases?
What is the meaning of above rejection reason?
How can i correct that?
What's wrong with the test cases?
I think what they want you to do is to write a spring web layer test. This is not a spring MVC test/spring-boot test. Because you don't test the controller as a spring loaded resource. You test it as a simple java class. That won't prove whether it behaves as a Spring controller correctly. You won't be able to test features such as;
spring resource injection
request dispatching and validation
How can i correct that?
You have to write a spring MVC test and use MockMvc or RestTemplate to verify your controller. For example;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = YourContext.class)
#WebAppConfiguration
public class MyWebTests {
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
#Test
public void foo() throws Exception {
mockMvc.perform(get("/status"));
//and verification
}
}
Usage of mockito mocks is not the worst idea, but you could have used auto wired #MockBeans.
If this is spring-boot, you will have more flexibility. Have a look at following resources.
https://docs.spring.io/spring/docs/current/spring-framework-reference/testing.html
https://spring.io/guides/gs/testing-web/
You have complaint because you don't need spring's test features in your test.
Your test is pure unit test.
So if you will remove #RunWith(SpringRunner.class) nothing will be changed for your test. Just put there #ExtendWith(MockitoExtension.class)
SpringRunner will initialize spring context for you test that you could inject or mock slice of your application using following annotations:
#MockBean
#Autowired
etc..

#Autowire in unit tests does not seem to work

I have a unit test setup using Mockito and Spring 4. My test looks like this:
#ContextConfiguration(classes = {
MyTestConfig.class,
SecurityConfig.class,
OAuth2Config.class
})
#RunWith(MockitoJUnitRunner.class)
public class ControllerAccessTests {
private MockMvc mockMvc;
#Autowired
private FilterChainProxy springSecurityFilterChain;
#Mock
private CreditCardPaymentService creditCardPaymentService;
#InjectMocks
private CreditCardRestController creditCardRestController;
#Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders
.standaloneSetup(creditCardRestController)
.apply(springSecurity(springSecurityFilterChain))
.build();
when(creditCardPaymentService.doPreAuthPayment(any())).thenReturn(null);
}
#Test
//.... some unit tests
With a configuration file that looks like this:
#Configuration
public class MyTestConfig {
#Bean
public FilterChainProxy springSecurityFilterChain(){
AntPathRequestMatcher matcher = new AntPathRequestMatcher("/**");
DefaultSecurityFilterChain chain = new DefaultSecurityFilterChain(matcher);
return new FilterChainProxy(chain);
}
}
When I start the unit test springSecurityFilterChain is null, so it seems the configuration file MyTestConfig does not seem to get loaded. Any ideas?
Cheers
Tom
If you want to use mockito annotations and spring injection then:
1) Use #RunWith(SpringJUnit4ClassRunner.class)
2) Create an init method:
#Before
public void init(){
MockitoAnnotations.initMocks(this);
}

With Spring, #InjectMock annotated test target doesn't use mocks

I'm trying to unit test a Spring 4.0.0 MVC application.
My controller is defined as follow:
#Controller
#RequestMapping("/test")
public class TestCtrl {
#Autowired
private TestService testService;
#Autowired
private TestRessourceAssembler testRessourceAssembler;
#Autowired
private ResponseComposer responseComposer;
#RequestMapping(value = "", method = RequestMethod.GET,produces = "application/json")
public HttpEntity showAll(Pageable pageable) {
Page<Test> patr = testService.getAll(pageable);
return responseComposer.composePage(patr,testRessourceAssembler);
}
#RequestMapping(value = "/{name}", method = RequestMethod.GET)
public HttpEntity<TestRessource> show(#PathVariable String name) {
Test test = testService.getOne(name);
if(test == null){
return new ResponseEntity("Erreur !",HttpStatus.NOT_FOUND);
}
return responseComposer.compose(test,testRessourceAssembler);
}
}
My controller unit test is as follow:
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles("test")
#WebAppConfiguration
#ContextConfiguration(classes = {ApplicationConfig.class, TestMongoConfig.class, RestConfig.class, WebMvcConfig.class})
public class TestCtrlTests{
#InjectMocks
TestCtrl testCtrl;
#Mock
TestService testService;
#Autowired
protected WebApplicationContext wac;
protected MockMvc mockMvc;
#Before
public void setup(){
MockitoAnnotations.initMocks(this);
when(testService.getOne("jexiste")).thenReturn(new com.thalesgroup.ito.c2s.mc.portail.test.domain.Test("jexiste",1990));
when(testService.getOne("plaf")).thenReturn(null);
this.mockMvc = webAppContextSetup(this.wac).build();
}
#Test
public void simpleGetAnswer() throws Exception{
assertNotNull(mockMvc);
mockMvc.perform(get("/test")).andExpect(status().isOk());
mockMvc.perform(get("/test/jexiste")).andExpect(status().isOk());
mockMvc.perform(get("/test/plaf")).andExpect(status().isNotFound());
}
}
When I'm running the test, the "normal" TestService bean is injected and used (I can see the trace in the log), not the mock.
So I read some things on the internet and replaced
this.mockMvc = webAppContextSetup(this.wac).build();
with
this.mockMvc = standaloneSetup(TestCtrl.class).build();
But, and I knew it would happen, I've no more Spring context when doing this, so my PageableArgumentResolver and my other beans (testRessourceAssembler, responseComposer) aren't injected anymore... So they are Null and happen a NullPointerException.
My question is:
1) I'm I designing something wrong ?
2) If not, how can I inject a mock in my controller while keeping other beans from the context ?
Thanks to you !
I'm looked into your tests and this should work. Simply build your MockMvc on your controller with mocked beans. After this all mocks will be visible inside test.
A MockMvcBuilder that accepts #Controller registrations thus allowing full control over the instantiation and the initialization of controllers and their dependencies similar to plain unit tests, and also making it possible to test one controller at a time.
Don't use Spring Integration test! This is simple unit testing!
Fixed test
#RunWith(MockitoJUnitRunner.class)
public class TestCtrlTests{
#InjectMocks
TestCtrl testCtrl;
#Mock
TestService testService;
protected MockMvc mockMvc;
#Before
public void setup(){
when(testService.getOne("jexiste")).thenReturn(new com.thalesgroup.ito.c2s.mc.portail.test.domain.Test("jexiste",1990));
when(testService.getOne("plaf")).thenReturn(null);
this.mockMvc = standaloneSetup(testCtrl).build();
}
#Test
public void simpleGetAnswer() throws Exception{
assertNotNull(mockMvc);
mockMvc.perform(get("/test")).andExpect(status().isOk());
mockMvc.perform(get("/test/jexiste")).andExpect(status().isOk());
mockMvc.perform(get("/test/plaf")).andExpect(status().isNotFound());
}
}

Categories