Integration test for Service/Rest methods in Java - java

As I mention in title, I need to create integration test.
This is my first test in my life.
I need that my integration test call a rest method but I'm getting this error:
This is My test:
#SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = CrewApplication.class)
#AutoConfigureMockMvc
#TestPropertySource(locations = "classpath:TeamController")
public class TeamIntegrationTest {
#Autowired
MockMvc mockMvc;
#Test
public void integrationTeamTest() throws Exception {
MvcResult mvcResult = mockMvc.perform(
MockMvcRequestBuilders.get("/teams")
.accept(MediaType.APPLICATION_JSON)
).andReturn();
System.out.println(mvcResult.getResponse());
}
}
And this is my rest method:
#RestController
public class TeamController {
private final TeamService teamService;
private final PersonService personService;
#Autowired
public TeamController(TeamService teamService, PersonService personService) {
this.teamService = teamService;
this.personService = personService;
}
#GetMapping("/teams")
public List<TeamDto> findAll() {
return teamService.findAll();
}
Method work, Junit test work only this integration throw error :
java.lang.NullPointerException

You are mixing Spring unit tests and Spring integration test.
When you want to do an Integrations test you have to actually make a call to the API.
#RunWith(SpringRunner.class)
#SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = CrewApplication.class)
public class TeamIntegrationTest {
#Autowired
private TestRestTemplate restTemplate;
#Test
public void integrationTeamTest() throws Exception {
String body = this.restTemplate.getForObject("/teams", String.class);
assertThat(body).isEqualTo("TEAM REPRESENTATION AS STRING");
}
}
If you need further information, visit Spring Documentation .

Related

how can i insert advanced data in spring boot test?

I'm making test code in spring boot.
But, my test code doesn't save the data using #Before method.
If i request to '/v1/stay/, it return empty array...
Please can you explain what is wrong with my code?
Here is my test code.
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class StayControllerTest {
#MockBean
private StayService stayService;
#Autowired
private MockMvc mockMvc;
// givenStay method is the method generating dummy data
#Before
public void before() {
stayService.save(givenStay1());
stayService.save(givenStay2());
stayService.save(givenStay3());
stayService.save(givenStay4());
stayService.save(givenStay5());
}
#Test
#Transactional
void showStayList() throws Exception {
List<StayReq> original = new ArrayList<>();
original.add(givenStay1());
original.add(givenStay2());
original.add(givenStay3());
original.add(givenStay4());
original.add(givenStay5());
MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/v1/stay")
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(print())
.andReturn();
System.out.println(result.getResponse());
}
}
And below code blocks are my StayController and StayService
#RestController
#ApiV1
#RequiredArgsConstructor
public class StayController {
private final StayService stayService;
private final ApiService apiService;
#GetMapping("/stay")
public ResponseEntity<Response> stayList() {
return apiService.okResponse(stayService.getList());
}
}
#Service
#RequiredArgsConstructor
public class StayService {
private final StayRepository stayRepository;
private final RoomRepository roomRepository;
public List<StayRes> getList() {
return stayRepository.findAll().stream().map(StayRes::new).collect(Collectors.toList());
}
#Transactional
public void save(StayReq stayReq) {
stayRepository.save(stayReq.toEntity());
}
}
You injected a mock, not a 'real' service. If you want to use a 'real' service - you need to replace #MockBean annotation with #Autowired annotation.
Or alternatively - you can configure mock in the test method to return some predefined data.

Integration test fails when attempting to auto configure via AutoConfigureMockMvc

I am writing a simple test for a controller endpoint.
It works fine when I do the following.
#SpringBootTest
#ContextConfiguration(classes = {
HomeController.class,
HomeControllerTest.class
})
class HomeControllerTest {
#Autowired
private WebApplicationContext webApplicationContext;
private static final String URL = "/a";
private static final ObjectMapper objectMapper = new ObjectMapper();
#Test
public void test() throws Exception {
MockMvc mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
Request request = new Request();
mockMvc.perform(post(URL)
.contentType("application/json")
.content(objectMapper.writeValueAsString(request))
.andExpect(status().isOk());
}
}
But I do not want to have to create the mockMvc and concern with webApplicationContext.
Thus instead, attempting to use #AutoConfigureMockMvc instead as follows.
But this doesn't work. Fails with following error.
java.lang.AssertionError: Status expected:<200> but was:<403> Expected
:200 Actual :403
What am I doing wrong?
My attempt which throws above error.
#SpringBootTest
#AutoConfigureMockMvc // using this annotation instead
#ContextConfiguration(classes = {
HomeController.class,
HomeControllerTest.class
})
class HomeControllerTest {
// wiring mockMvc instead
// no webApplicationContext autowired
#Autowired
private MockMvc mockMvc;
private static final String URL = "/a";
private static final ObjectMapper objectMapper = new ObjectMapper();
#Test
public void test() throws Exception {
Request request = new Request();
mockMvc.perform(post(URL)
.contentType("application/json")
.content(objectMapper.writeValueAsString(request))
.andExpect(status().isOk());
}
}
Try create test like this exemple it is better.
#SpringBootTest
#AutoConfigureMockMvc
public class HomeControllerTest
private ObjectMapper mapper;
private MyControler myController;
private ServiceInSideConttroler service;
add your atributes
#Before
public init(){
this.mapper = new ObjectMapperConfiguration().mapper();
this.service = mock(ServiceInSideConttroler.class);
this.myController = new MyController(service);
}
#Test
public void test() throws Exception {
// exemple how mock reponse from any service or repository.
when(service.findById(any(Long.class)))
.thenReturn(Optional.of(budget));
Object resp = myController.save(mockben());
......
aserts(resp)
}
}
Remember, to work with the tests like this, do not use #Authwired in the attributes, only in the constructor of the classes annotated with #service, #componet, #controller etc .... that is, any class controlled by Spring that will use dependecia injection. Also rember asserts your reponse.

Unit tests using Mockito

I'm new to unit tests and well, I'm struggling to understand how it should be done.
I have some methods with #RequestParam and I'm not sure how to mock this.
It would be great if I had an example I could apply to the other methods.
Could you help me by writing the test method for this one? It would be very useful.
#PutMapping("/player/update-password")
public ResponseEntity<?> updatePlayerPassword(#RequestParam("token") String token, #RequestParam("password") String newPassword) throws URISyntaxException {
String message = bundle.getString("put_player");
log.debug(message, token, newPassword);
PlayerEntity player = playerService.updatePassword(token, newPassword);
return new ResponseEntity<>(PlayerMapper.INSTANCE.mapPlayer(player), HttpStatus.ACCEPTED);
}
Thanks.
You can use #Mock and #InjectMocks annotations. With it you can inject mocks to your controller.
#Mock
PlayerService playerServiceMock;
And use when().then() from Mockito inside test or method with #Before annotation:
when(playerServiceMock.updatePassword(anyString(), anyString())).thenReturn(playerEntity);
The same can be done for bundle.getString("put_player").
Hoping you are using the Mockito. You can try the below code, need to add all imports
#RunWith(MockitoJUnitRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.MOCK)
public class YourClassNameTest {
#Autowired
MockMvc mockMvc;
#InjectMocks
YourClassName yourClassName;
#Mock
PlayerService playerService;
#Before
public void Setup() {
mockMvc = MockMvcBuilders.standaloneSetup(yourClassName);
}
#Test
public void updatePlayerPasswordTest() throws Exception {
PlayerEntity player = new PlayerEntity();
// set some date if you want
Mockito.when(playerService.updatePassword(anyString(), anyString())).thenReturn(player);
RequestBuilder requestBuilder = MockMvcRequestBuilders
.get("/player/update-password?token=abc&password=test")
.accept(MediaType.APPLICATION_JSON);
mockMvc.perform(requestBuilder).andExpect(MockMvcResultMatchers.status().isCreated());
}
}

Mock embedded objects in integration test

Trying to write an integration test for a Spring application. Say i've got a class A which contains a class B object. Class B contains a class C object and I need to mock an object within this class for the integration test - any idea how i go about doing that without passing every object through as a parameter in the constructor?
e.g.
#Service
Class A {
#Autowired
private B b;
public void testA() {
B.testB();
}
}
#Service
Class B {
#Autowired
private C c;
public void testB() {
c.testC();
}
}
#Service
Class C {
//External class pulled in from dependency library
#Autowired
private RestTemplate restTemplate;
public void testC() {
restTemplate.doSomethingInOutsideWorld();
}
}
Integration test:
#RunWith(JUnitParamsRunner.class)
#SpringBootTest
public class MyIt {
#ClassRule
public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
#Rule
public final SpringMethodRule springMethodRule = new SpringMethodRule();
#Mock
private RestTemplate restTemplate;
#Autowired
private A a;
#InjectMocks
private C c;
#Before
public void setup() {
initMocks(this);
}
#Test
public void test1() throws IOException {
a.testA()
}
}
Doesn't mock the RestTemplate object, it tries to hit the outside world. Any advice on how to resolve this?
Achieve this by using SpringRunner and #MockBean
#RunWith(SpringRunner.class) is used to provide a bridge between Spring Boot test features and JUnit. Whenever we are using any Spring Boot testing features in out JUnit tests, this annotation will be required.
The #SpringBootTest annotation can be used when we need to bootstrap the entire container. The annotation works by creating the ApplicationContext that will be utilized in our tests.
Annotation that can be used to add mocks to a Spring ApplicationContext. Can be used as a class level annotation or on fields in either #Configuration classes, or test classes that are #RunWith the SpringRunner.
#RunWith(SpringRunner.class)
#SpringBootTest
public class MyIt {
#MockBean
private RestTemplate restTemplate;
#Autowired
private A a;
#Before
public void setup() {
initMocks(this);
}
#Test
public void test1() throws IOException {
given(this.restTemplate.doSomethingInOutsideWorld()).willReturn(custom object);
a.testA()
}
}

Spring MVC Test failing

I am trying to run a Spring MVC Test but keep getting this exception.
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException
The exception is occuring because the autowired dependency,
#Autowired
private AccountService accountService;
is not getting injected in the test (works fine outside of the test).
Can anyone help me with this. Here is my code:
//AccountControllerITest Class
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = MockServletContext.class)
#WebAppConfiguration
public class AccountControllerITest {
private MockMvc mvc;
ObjectMapper om;
#Before
public void setUp() throws Exception {
mvc = MockMvcBuilders.standaloneSetup(new AccountController()).build();
}
#Test
public void getAccounts() throws Exception {
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.get("/api/accounts"))
.andExpect(status().isOk())
.andReturn();
}
}
}
//AccountController
#RestController
#RequestMapping("/api/accounts")
public class AccountController {
#Autowired
private AccountService accountService;
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<Set<AccountInfo>> getAccounts(#RequestParam(value = "firstName", required = false) String firstName,
#RequestParam(value = "surName", required = false) String surName) {
Set<AccountInfo> accounts = accountService.getAccounts(firstName, surName);
return new ResponseEntity<>(accounts, HttpStatus.OK);
}
}
Thanks for the help!
Because you are using standalone setup: mvc = MockMvcBuilders.standaloneSetup(new AccountController()).build();. If you create controller via new AccountController(), Spring doesn't have a chance to inject accountService as it doesn't control instances creation and wiring.
You have two options:
Switch your test to unit test and do not use SpringJUnit4ClassRunner nor MockServletContext at
all. You can use #InjectMocks to inject private accountService:
public class AccountControllerITest {
private MockMvc mvc;
ObjectMapper om;
#Mock
private AccountController accountController = new AccountController();
#InjectMocks
private AccountService accountService = new Mockito.mock(AccountService.class);
#Before
public void setUp() throws Exception {
mvc = MockMvcBuilders.standaloneSetup(accountController).build();
}
There is also enhancement you can apply to your controller. Replace field injection with constructor injection and you can pass accountService to controller via constructor in test. This way you don't need to use #InjectMocks at all.
Use webAppContext setup:
#Autowired
private WebApplicationContext webApplicationContext;
#BeforeMethod
public void init() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
You need to configure your test to inject your autowired properties. See the following code block:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
public class AccountControllerITest {
// ... your test code
#Configuration
public static class YourConfiguration {
#Bean
AccountService accountService() {
// init and return your AccountService
}
}
}
You can init your AccountService with Mockito.

Categories

Resources