Autowired MockMvc is null with JUnit 5 and Spring boot - java

I have a class test which send me an error when I run the test.
I followed several threads and I have the right import "import org.junit.jupiter.api.Test"
So I don't understand why it sends me this error :
Cannot invoke "org.springframework.test.web.servlet.MockMvc.perform(org.springframework.test.web.servlet.RequestBuilder)" because "this.mockMvc" is null
My code :
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#WebMvcTest(TestController.class)
public class ControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private CreateMessageProvider createMessageProvider;
#Test
public void test() throws Exception {
this.mockMvc.perform(get("/test"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string("OK"));
}
}
Gradle config :
mockitoCoreVersion = '4.6.1'
mockitoJunitJupiterVersion = '4.6.1'
springBootTestVersion = '2.7.2'
springTestVersion = '5.3.22'
testImplementation "org.springframework.boot:spring-boot-test:$springBootTestVersion"
testImplementation "org.springframework:spring-test:$springTestVersion"
testImplementation "org.mockito:mockito-junit-jupiter:$mockitoJunitJupiterVersion"
testImplementation "org.mockito:mockito-core:$mockitoCoreVersion"
EDIT : I found the solution. My gradle file didn't have this dependency :
testImplementation "org.springframework.boot:spring-boot-starter-test:2.7.2"

Try
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#AutoConfigureMockMvc
#SpringBootTest
public class ControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private CreateMessageProvider createMessageProvider;
#Test
public void test() throws Exception {
this.mockMvc.perform(get("/test"))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string("OK"));
}
}

Use these annotations :
#RunWith(SpringRunner.class)
#AutoConfigureMockMvc
#ExtendWith({RestDocumentationExtension.class, SpringExtension.class})

Related

Why does #InjectMocks in Java Spring return null in my test case for a service?

I am trying to write test cases for a service I have implemented for a controller in Spring. I have the following Service and Test classes.
StudentCourseRequestService:
import java.util.List;
import org.springframework.stereotype.Service;
import model.CourseRequest;
import repository.ICourseRequestRepository;
import lombok.RequiredArgsConstructor;
#Service
#RequiredArgsConstructor
public class StudentCourseRequestService implements IStudentCourseRequestService {
private final ICourseRequestRepository courseRequestRepository;
#Override
public boolean requestCourse(CourseRequest courseRequest) {
return courseRequestRepository.saveRequest(courseRequest);
}
#Override
public List<CourseRequest> getAllCourseRequests() {
return courseRequestRepository.getAllCourseRequests();
}
#Override
public List<CourseRequest> getAllCourseRequestsOfStudent(Long studentId) {
return courseRequestRepository.getCourseRequestsByStudentId(studentId);
}
}
Test class:
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.springframework.boot.test.mock.mockito.MockBean;
import static org.assertj.core.api.Assertions.assertThat;
import model.CourseRequest;
import repository.ICourseRequestRepository;
public class StudentCourseRequestServiceTests {
#MockBean
private ICourseRequestRepository courseRequestRepository;
#InjectMocks
private StudentCourseRequestService studentCourseRequestService;
#Test
public void requestValidCourse() throws Exception {
final CourseRequest courseRequest = new CourseRequest(
"data0",
"data1",
"data2",
"data3",
"data4",
"data5"
);
Mockito.when(courseRequestRepository.saveRequest(courseRequest)).thenReturn(true);
boolean result = studentCourseRequestService.requestCourse(courseRequest);
assertThat(result).isTrue();
}
}
When I run the requestValidCourse() test case, I get the following error:
java.lang.NullPointerException: Cannot invoke "repository.ICourseRequestRepository.saveRequest(model.CourseRequest)" because "this.courseRequestRepository" is null
at service.StudentCourseRequestServiceTests.requestValidCourse(StudentCourseRequestServiceTests.java:29)
at java.base/java.util.ArrayList.forEach(Unknown Source)
at java.base/java.util.ArrayList.forEach(Unknown Source)
How can I resolve this issue?
As #Lesiak recommended, I added the #ExtendWith(MockitoExtension.class) annotation to the top of the class, and changed courseRequestRepository to have the #Mock annotation, instead of the previous #MockBean annotation. The issue got resolved after these changes.
Previously I had the configuration recommended by #Lesiak during my trials to resolve the issue, but I also had the annotation #ExtendWith(SpringExtension.class) at the top of the class. With this configuration, I got the same error. Removing the #ExtendWith(SpringExtension.class) annotation resolved the issue here.
New test class:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.assertj.core.api.Assertions.assertThat;
import model.CourseRequest;
import repository.ICourseRequestRepository;
#ExtendWith(MockitoExtension.class)
public class StudentCourseRequestServiceTests {
#Mock
private ICourseRequestRepository courseRequestRepository;
#InjectMocks
private StudentCourseRequestService studentCourseRequestService;
#Test
public void requestValidCourse() throws Exception {
final CourseRequest courseRequest = new CourseRequest(
"data0",
"data1",
"data2",
"data3",
"data4",
"data5"
);
Mockito.when(courseRequestRepository.saveRequest(courseRequest)).thenReturn(true);
boolean result = studentCourseRequestService.requestCourse(courseRequest);
assertThat(result).isTrue();
}
}

MockMvc Not working when Controller is in different package (JUnit5)

package com.azry.ptm.api;
import com.azry.ptm.api.model.account.AccountDTO;
import com.azry.ptm.domain.account.Account;
import com.azry.ptm.server.services.AccountService;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpStatus;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.web.servlet.MockMvc;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.mockito.ArgumentMatchers.anyLong;
#AutoConfigureMockMvc
#SpringBootTest
public class AccountControllerImplTest {
#Autowired
private MockMvc mockMvc;
#MockBean
public AccountService accountService;
#Test
public void test() throws Exception {
final long entityNo = 10;
Account expectedAccount = Account.builder()
.entityNo(entityNo)
.build();
Mockito.when(accountService.getAccountById(anyLong())).thenReturn(Optional.of(expectedAccount));
MockHttpServletResponse response = mockMvc.perform(ControllerTestHelper.makeGetRequest("account/", String.valueOf(entityNo)))
.andReturn()
.getResponse();
AccountDTO responseAccount = ControllerTestHelper.toObject(response.getContentAsString(), AccountDTO.class);
assertEquals(HttpStatus.OK.value(), response.getStatus());
assertNotNull(responseAccount);
}
}
Here is my mockMvc test. it works only when the controller is in the same module es test, otherwise, when I split the project it returns a 404 error code as no endpoint was found.
has anybody experience using mockMvc in a multi-module spring-boot app?
solved using #WebMvcTest annotation
#WebMvcTest(AccountControllerImpl.class)

How to Use FakeMongo and Ignore MongoDB socket connection on Controller level Integration testing

I am using spring boot 1.5.x for application. Database is MONGO
Using MongoRepository for crud operations.
Earlier in our project we got dedicated test database instance so we have added mongodb properties of test db in src\test\resources\application.properties.
Now we dont have test db so we want to use embedded/fake db to test our classes Controller/Services/Repository etc..
Options are - embeded mongodb like flapdoodle and fongo
I tried 1 of solution de.flapdoodle.embed.mongo from SO question to use flapdoodle
de.flapdoodle.embed.mongo trying to download zip outside network : unable-to-download-embedded-mongodb-behind-proxy-using-automatic-configuration
I tried fakemongo but its not working for unit and integration testing of controller. Its picking mongo database details of test db using application.properties present in test/resources
pom.xml
<dependency>
<groupId>com.github.fakemongo</groupId>
<artifactId>fongo</artifactId>
<version>${fongo.version}</version>
<!--<scope>test</scope> -->// not working, if removed it says cannot find mongo
</dependency>
<dependency>
<groupId>com.lordofthejars</groupId>
<artifactId>nosqlunit-mongodb</artifactId>
<version>0.7.6</version>
<scope>test</scope>
</dependency>
FakeMongo Configuration
package com.myapp.config;
import com.github.fakemongo.Fongo;
import com.mongodb.MongoClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.AbstractMongoConfiguration;
#Configuration
#EnableMongoRepositories
public class FakeMongo extends AbstractMongoConfiguration {
#Override
protected String getDatabaseName() {
return "mockDB";
}
#Bean
public MongoClient mongo() {
Fongo fongo = new Fongo("mockDB");
return fongo.getMongo();
}
}
TestFakeMongo It works. Test executed properly - Reference http://springboot.gluecoders.com/testing-mongodb-springdata.html
package com.myapp.config;
import com.myapp.domain.entitlement.User;
import com.myapp.repository.UserRepository;
import com.lordofthejars.nosqlunit.annotation.UsingDataSet;
import com.lordofthejars.nosqlunit.core.LoadStrategyEnum;
import com.lordofthejars.nosqlunit.mongodb.MongoDbRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
import static com.lordofthejars.nosqlunit.mongodb.MongoDbRule.MongoDbRuleBuilder.newMongoDbRule;
import static org.junit.Assert.assertTrue;
#RunWith(SpringRunner.class)
#Import(value = {FakeMongo.class})
public class TestFakeMongo {
#Autowired
private ApplicationContext applicationContext;
#Rule
public MongoDbRule embeddedMongoDbRule = newMongoDbRule().defaultSpringMongoDb("mockDB");
#MockBean
private UserRepository userRepository;
#Test
#UsingDataSet(loadStrategy = LoadStrategyEnum.DELETE_ALL)
public void getAllUsers_NoUsers() {
List<User> users = userRepository.findAll();
assertTrue("users list should be empty", users.isEmpty());
}
}
UserRepositoryTest - Unit testing for Repository also working using fongo Reference - http://dontpanic.42.nl/2015/02/in-memory-mongodb-for-unit-and.html
package com.myapp.repository;
import com.myapp.config.SpringUnitTest;
import com.myapp.domain.User;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.*;
public class UserRepositoryTest extends SpringUnitTest {
#Autowired
private UserRepository userRepository;
#Before
public void setup() {
importJSON("user", "user/user.json");
}
#Test
//#UsingDataSet(loadStrategy = LoadStrategyEnum.CLEAN_INSERT, locations = "/json-data/user/user.json") // test/resources/..
public void findUser_should_return_user() {
User user = userRepository.findByXYZId("XX12345");
assertNotNull(user);
}
#Test
public void findUser_should_return_null() {
User user = userRepository.findByXYZId("XX99999");
assertNull(user);
}
#Test
public void deleteUser_should_return_null() {
userRepository.delete("XX12345");
User user = userRepository.findByXYZId("XX12345");
assertNull(user);
}
#Test
public void saveUser_should_return_user() {
User user = new User();
user.setXYZId("XX12345");
user.setAck(true);
List<DateTime> dateTimeList = new ArrayList<>();
dateTimeList.add(DateTime.now(DateTimeZone.UTC));
user.setAckOn(dateTimeList);
User dbUser = userRepository.save(user);
assertEquals(user, dbUser);
}
#Test
public void findAllUser_should_return_users() {
List<User> userList = userRepository.findAll();
assertEquals(1, userList.size());
}
}
Controller level testing not working.. Reference- https://www.paradigmadigital.com/dev/tests-integrados-spring-boot-fongo/
UserControllerTest failed java.lang.IllegalStateException: Failed to load ApplicationContext - At this point test mongo db details fetech instead of fongo test\resources\application.properties test server db details are loading
package com.myapp.config;
package com.myapp.controllers;
import com.myapp.config.FakeMongo;
import com.myapp.services.persistance.UserService;
import com.lordofthejars.nosqlunit.mongodb.MongoDbRule;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultMatcher;
import static com.lordofthejars.nosqlunit.mongodb.MongoDbRule.MongoDbRuleBuilder.newMongoDbRule;
import static org.hamcrest.CoreMatchers.containsString;
import static org.springframework.test.web.client.match.MockRestRequestMatchers.content;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#ActiveProfiles("it")
#RunWith(SpringRunner.class)
#SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = Application.class
)
#Import(value = {FakeMongo.class})
#AutoConfigureMockMvc
#TestPropertySource(locations = "classpath:application-it.properties")
public class UserControllerTest {
#Rule
public MongoDbRule embeddedMongoDbRule = newMongoDbRule().defaultSpringMongoDb("mockDB");
#Autowired
private MockMvc mockMvc;
#MockBean
private UserService service;
#Before
public void setUp() throws Exception {
}
#Test
public void deleteUser() throws Exception {
Mockito.when(this.service.deleteUser(Mockito.anyString())).thenReturn(true);
this.mockMvc.perform(delete("/User")).andDo(print()).andExpect(status().isOk())
.andExpect((ResultMatcher) content().string(containsString("true")));
}
}
UserControllerTest Not working, failing with error java.lang.IllegalStateException: Failed to load ApplicationContext as its tries to connect to test instance of mongo database using application.properties present in test/resources
Appreciate working example to use fakemongo while running Integration test for Controller level
What changes, I need to do in code level(Controller class or any other class) or application.properties of test\resources ?

Spring Cloud Contract not executing #Before

I am writing tests using Spring Cloud Contract.
In my configuration I am using for test an in memory DB that is created and destroyed at each test run.
In order to test successfully I need to put some data in the DB but it seems like the classic #Before annotation used in jUnit does not work (the code in it is never executed).
import io.restassured.module.mockmvc.RestAssuredMockMvc;
import org.junit.Before;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.web.context.WebApplicationContext;
#ExtendWith(SpringExtension.class)
#SpringBootTest
public class BaseTestClass {
private static final Logger LOGGER = LoggerFactory.getLogger(BaseTestClass.class);
#Autowired
EntityRepository entityRepository;
#Autowired
private WebApplicationContext context;
#Before
public void init() {
// This code never runs
LOGGER.info("Init started");
MyEntity entity1 = new MyEntity();
entityRepository.save(entity1);
}
#BeforeEach
public void setup() {
RestAssuredMockMvc.webAppContextSetup(context);
}
}
What am I missing?
#Before belongs to JUnit4 and earlier while #BeforeEach belongs to JUnit5 as a replacement and clarification of #Before. If you are running with JUnit5, perhaps put all your initialization logic in #BeforeEach (or if it's a one-time init, in #BeforeAll)
I've found a solution that works.
I was adding the #TestInstance decorator incorrectly, here's my working solution:
import io.restassured.module.mockmvc.RestAssuredMockMvc;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.web.context.WebApplicationContext;
#ExtendWith(SpringExtension.class)
#SpringBootTest
#TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class BaseTestClass {
private static final Logger LOGGER = LoggerFactory.getLogger(BaseTestClass.class);
#Autowired
EntityRepository entityRepository;
#Autowired
private WebApplicationContext context;
#BeforeAll
public void init() {
LOGGER.info("Init started");
MyEntity entity1 = new MyEntity();
entityRepository.save(entity1);
}
#BeforeEach
public void setup() {
RestAssuredMockMvc.webAppContextSetup(context);
}
}

Junit throwing initialization error. Method 'com' not found

All the tests are passing . What should I add for this error to disappear? I am assuming some annotation need to be added. It says Method 'com' not found. I am not able to debug . I dont know what is it talking about.
Code:
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#SpringBootTest
public class test {
#Autowired
private JdbcTemplate jdbcTemplate;
#Autowired
private JdbcImpl jdbcImpl;
#Autowired
private MConfiguration config;
#Autowired
private MUtilities util;
#Test
public void testRetervices() throws Exception {
List<Tervice> marketServices = jdbcImpl.retrieveTervices("em", "Coitis");
assertEquals(marketServices.size(), 4);
}
Thanks for your time.
This got fixed when I changed the package from
import org.junit.jupiter.api.Test; to
import org.junit.Test;
Thanks!

Categories