Spring Boot - unit test not detecting the controller test - spring-boot

I have written unit test for the controller class but when I run unit test using "mvn test" or directly from "SpringBootDemo1ApplicationTests" only test under "SpringBootDemo1ApplicationTests" class runs, and it doesn't pick up test from "BookControllerTest" class.
SpringBootDemo1ApplicationTests.java:
package com.sprboot.SpringBootDemo1;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
#SpringBootTest
class SpringBootDemo1ApplicationTests {
#Test
void contextLoads() {
}
}
BookControllerTest.java
package com.sprboot.SpringBootDemo1;
import com.sprboot.SpringBootDemo1.controllers.BookController;
import com.sprboot.SpringBootDemo1.models.Book;
import com.sprboot.SpringBootDemo1.services.BookService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.json.AutoConfigureJsonTesters;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.json.JacksonTester;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.web.servlet.MockMvc;
import java.util.Optional;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
import static org.mockito.BDDMockito.given;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
#AutoConfigureJsonTesters
#WebMvcTest(BookController.class)
#SpringBootTest
public class BookControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private BookService bookService;
#Autowired
private JacksonTester<Book> jsonBook;
#Test
private void canRetriveBookById() throws Exception {
given(bookService.getBookByID(123)).willReturn(Optional.of(new Book(123, "test book")));
MockHttpServletResponse response = mockMvc.perform(
get("/getBookById/123")
.accept(MediaType.APPLICATION_JSON))
.andReturn().getResponse();
// then
assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
assertThat(response.getContentAsString()).isEqualTo(
jsonBook.write(new Book(1, "test book")).getJson()
);
}
private void canRetriveBookByIdV2() throws Exception {
given(bookService.getBookByID(123)).willReturn(Optional.of(new Book(123, "test book")));
MockHttpServletResponse response = mockMvc.perform(
get("/getBookById/123")
.accept(MediaType.APPLICATION_JSON))
.andReturn().getResponse();
// then
assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
assertThat(response.getContentAsString()).isEqualTo(
jsonBook.write(new Book(1, "test book")).getJson()
);
}
}
I was expecting test "canRetriveBookById" to run as well but only test "contextLoads" runs, not sure whats wrong here.

It's because your #Test method is private.
From the #Test annotations documentation:
#Test methods must not be private or static and must not return a value.

Related

spring boot unit test can not resolve get

why inteli J can not resolve get in my unit test ?
package com.stev.pillecons.pilleCons;
import com.stev.pillecons.pilleCons.controllers.LePilleController;
import com.stev.pillecons.pilleCons.services.PilleService;
import org.junit.Test;
import org.junit.runner.RunWith;
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.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
#RunWith(SpringRunner.class)
#WebMvcTest(LePilleController.class)
public class UnitTestPille {
#Autowired
private MockMvc mockMvc;
#MockBean
PilleService pilleService;
#Test
public void getAllPille() throws Exception {
mockMvc.perform(get("/api/pille"))
.andExpect(status().isOk())
.andExpect(content())
}
}
all get(),status(), and content() are Red
You are missing the static imports:
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

How to correctly stop and start a localstack instance

I am using Localstack to write integration tests. One of the scenarios I want to test is when the AWS service throws error. My test looks like
void saveEventsAsync_snsError() throws Exception{
localSns.stop();
mvc.perform( MockMvcRequestBuilders
.post("/events-async")
.content(validRequest())
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isInternalServerError());
}
However doing do fails one another test with HttpConnection refused.. error. Presumably the container didn't start by the time the test ran.
What are my options here ? Looping with localSns.isRunning() doesn;t seem to help
Here's full test clas for reference
package ....
import org.junit.jupiter.api.*;
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.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Profile;
import org.springframework.http.MediaType;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.testcontainers.containers.localstack.LocalStackContainer;
import org.testcontainers.containers.wait.strategy.DockerHealthcheckWaitStrategy;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sns.SnsClient;
import software.amazon.awssdk.services.sns.model.CreateTopicRequest;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.testcontainers.containers.localstack.LocalStackContainer.Service.SNS;
#SpringBootTest
#AutoConfigureMockMvc
#ActiveProfiles("test")
#Testcontainers
#TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class EventReportingControllerTest {
#Autowired
MockMvc mvc;
#Container
private static final LocalStackContainer localSns =
new LocalStackContainer(DockerImageName.parse("localstack/localstack:0.11.3"))
.withServices(SNS);
private static SnsClient snsClient;
private static String topicArn ;
#BeforeAll
static void beforeAll() {
localSns.start();
snsClient = SnsClient.builder()
.endpointOverride(localSns.getEndpointOverride(SNS))
.credentialsProvider(
StaticCredentialsProvider.create(
AwsBasicCredentials.create(localSns.getAccessKey(), localSns.getSecretKey())
)
)
.region(Region.of(localSns.getRegion()))
.build();
topicArn = snsClient.createTopic(CreateTopicRequest.builder().name("testTopic").build()).topicArn();
}
#DynamicPropertySource
public static void overrideProps(DynamicPropertyRegistry registry){
registry.add("events.sns.topic.arn", () -> snsClient.createTopic(CreateTopicRequest.builder().name("testTopic").build()).topicArn());
}
#TestConfiguration
public static class SnsClientConfig {
#Bean
#Profile("test")
public SnsClient amazonSNSClient() {
return snsClient;
}
}
#Test
void saveEventsAsync_success() throws Exception{
mvc.perform( MockMvcRequestBuilders
.post("/events-async")
.content(validRequest())
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isAccepted()
);
}
#Test
void saveEventsAsync_invalidRequest() throws Exception{
mvc.perform( MockMvcRequestBuilders
.post("/events-async")
.content(invalidRequest())
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isBadRequest());
}
#Test
void saveEventsAsync_snsError() throws Exception{
localSns.stop();
mvc.perform( MockMvcRequestBuilders
.post("/events-async")
.content(validRequest())
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isInternalServerError());
}
}
When using #Testconainers and #Container for your setup, Testcontainers will manage the lifecycle of the container for you.
Hence, you currently have a mix of self-manging and "managed by Testcontainers".
If you want to take over the lifecycle handling, remove the two annotations and start/stop the container according to your preference.
PS: If you're using a recent Spring Cloud AWS version, overriding the AWS SDK client is way simpler now.

Junit test cases for Rest API using Junit and Mockito

Junit test cases for API's
I'm new to Junit and Mockito, trying to write unit test cases for my controller class to test my APIs.
Here is the controller class
package com.mylearnings.controller;
import com.mylearnings.modal.Product;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
#RestController
public class ProductController {
private HashMap<String, Product> productCatalog = new HashMap<>();
#PostMapping("/product")
public ResponseEntity addProduct(#RequestBody Product product) {
productCatalog.put(product.getId(), product);
return new ResponseEntity("product added successfully", HttpStatus.CREATED);
}
#GetMapping("/product/{id}")
public ResponseEntity getProductDetails(#PathVariable String id) {
return ResponseEntity.ok(productCatalog.get(id));
}
#GetMapping("/product")
public List<Product> getProductList() {
return new ArrayList<>(productCatalog.values());
}
#PutMapping("/product")
public String updateProduct(#RequestBody Product product) {
productCatalog.put(product.getId(), product);
return "product updated successfully";
}
#DeleteMapping("/product/{id}")
public String deleteProduct(#PathVariable String id) {
productCatalog.remove(id);
return "product deleted successfully";
}
}
I have tried the following
Added #ExtendWith(MockitoExtension.class) and tried but still it's failing
package com.mylearnings.controller;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mylearnings.modal.Product;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
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.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.web.context.WebApplicationContext;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
#SpringBootTest
#AutoConfigureMockMvc
public class ProductControllerTest {
#Autowired
private MockMvc mockMvc;
#Autowired
private WebApplicationContext webApplicationContext;
#Mock
private Map<String, Product> productCatalog;
#InjectMocks
private ProductController productController;
#Test
public void testAddProduct() throws Exception {
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/product").contentType(MediaType.APPLICATION_JSON).content(new ObjectMapper().writeValueAsString(new Product("MS116", "Dell MS116", "Dell MS116 Usb wired optical mouse", "", 229d)))).andReturn();
assertEquals(201, mvcResult.getResponse().getStatus());
}
#Test
public void testGetProductDetails() throws Exception {
Product product = new Product("MS116", "Dell MS116", "Dell MS116 Usb wired optical mouse", "", 229d);
when(productCatalog.get("MS116")).thenReturn(product);
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/product/{id}", "MS116").accept(MediaType.APPLICATION_JSON)).andReturn();
assertEquals(200, mvcResult.getResponse().getStatus());
Product result = new ObjectMapper().readValue(mvcResult.getResponse().getContentAsString(), Product.class);
assertEquals(product, result);
}
}
the test case testGetProductDetails() is failing, I'm not sure whether it is because of map?
In order to be able to inject mocks into Application context using (#Mock and #InjectMocks) and make it available for you MockMvc, you can try to init MockMvc in the standalone mode with the only ProductController instance enabled (the one that you have just mocked).
Example:
package com.mylearnings.controller;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
import com.mylearnings.controller.Product;
import com.mylearnings.controller.ProductController;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.HashMap;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
#ExtendWith(MockitoExtension.class)
public class ProductControllerTest {
private MockMvc mockMvc;
#Mock
private HashMap<String, Product> productCatalog;
#InjectMocks
private ProductController productController;
#BeforeEach
public void setup() {
mockMvc = MockMvcBuilders.standaloneSetup(productController)
.build();
}
#Test
public void testAddProduct() throws Exception {
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.post("/product").contentType(MediaType.APPLICATION_JSON)
.content(new ObjectMapper().writeValueAsString(new Product("MS116", "Dell MS116", "Dell MS116 Usb wired optical mouse", "", 229d))))
.andReturn();
assertEquals(201, mvcResult.getResponse().getStatus());
}
#Test
public void testGetProductDetails() throws Exception {
Product product = new Product("MS116", "Dell MS116", "Dell MS116 Usb wired optical mouse", "", 229d);
when(productCatalog.get("MS116")).thenReturn(product);
MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/product/{id}", "MS116").accept(MediaType.APPLICATION_JSON)).andReturn();
assertEquals(200, mvcResult.getResponse().getStatus());
Product result = new ObjectMapper().readValue(mvcResult.getResponse().getContentAsString(), Product.class);
assertEquals(product, result);
}
}

java.lang.IllegalStateException: Unable to find a #SpringBootConfiguration, you need to use #ContextConfiguration or #SpringBootTest(classes=...)

Hey i have started learning spring-boot junit testing using spring boot Test framework at the time of creating the test case i am facing issues below .
how to resolve this issue.
java.lang.IllegalStateException: Unable to find a #SpringBootConfiguration, you need to use #ContextConfiguration or #SpringBootTest(classes=...) with your test
at org.springframework.util.Assert.state(Assert.java:70)
at org.springframework.boot.test.context.SpringBootTestContextBootstrapper.getOrFindConfigurationClasses(SpringBootTestContextBootstrapper.java:202)
at org.springframework.boot.test.context.SpringBootTestContextBootstrapper.processMergedContextConfiguration(SpringBootTestContextBootstrapper.java:137)
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildMergedContextConfiguration(AbstractTestContextBootstrapper.java:409)
at org.springframework.test.context.support.AbstractTestContextBootstrapper.buildDefaultMergedContextConfiguration(AbstractTestContextBootstrapper.java:323)
this is my RentalCarSystemApplicationTests.java
package com.test.project.rentalcarsystem;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#SpringBootTest
public class RentalCarSystemApplicationTests {
#Test
public void contextLoads()
{
}
}
this is my TestWebApp.java
package com.test.project.rentalcarsystem;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.springframework.web.context.WebApplicationContext;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
public class TestWebApp extends RentalCarSystemApplicationTests {
#Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
#Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
#Test
public void testEmployee() throws Exception {
mockMvc.perform(get("/car")).andExpect(status().isOk())
.andExpect(content().contentType("application/json;charset=UTF-8"))
.andExpect(jsonPath("$.setMilleage").value("24")).andExpect(jsonPath("$.setModelname").value("BMW"))
.andExpect(jsonPath("$.setSeating_capacity").value("5")).andExpect(jsonPath("$.setType").value("SUV"))
.andExpect(jsonPath("$.setCost").value("3000")).andExpect(jsonPath("$.setEmail").value("demo#gmail.com"))
.andExpect(jsonPath("$.setNumber").value("9845658789")).andExpect(jsonPath("$.setPincode").value(560036));
}
}
From the error logs it gives hint to use classes attribute for #SpringBootTest so
Change #SpringBootTest to #SpringBootTest(classes = Application.class)
Give a fully classified name of the class like below.
#SpringBootTest(classes=com.package.path.class)
Also refer this thread

Spring controller tests with mocks

So I'm having some issues coming up with a solution for a test.
This is the method I want to test(I'm new to this). It clears all fields on a web page each time it's loaded.
#RequestMapping("/addaddressform")
public String addAddressForm(HttpSession session)
{
session.removeAttribute("firstname");
session.removeAttribute("surname");
session.removeAttribute("phone");
session.removeAttribute("workno");
session.removeAttribute("homeno");
session.removeAttribute("address");
session.removeAttribute("email");
return "simpleforms/addContact";
}
and here's what i have so far for the test
package ControllerTests;
import java.text.AttributedCharacterIterator.Attribute;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration (classes = {SimpleFormsControllerTest.class})
public class SimpleFormsControllerTest {
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
#Test
public void addAddressForm_ExistingContactDetailsInForm_RemovalFromSession() throws Exception{
MockHttpSession mockSession = new MockHttpSession();
mockSession.putValue("firstname", "test");
mockSession.putValue("surname", "test");
mockSession.putValue("phone", "test");
mockSession.putValue("workno", "test");
mockSession.putValue("homeno", "test");
mockSession.putValue("address", "test");
mockSession.putValue("email", "test");
mockMvc.perform(get("simpleForms/addaddressform").session(mockSession));
}
As this is the first time I've ever had to do this kind of thing I don't have much clue where to go with this.
Then you have to do is only assert the values, e.g.:
assertNull(mockSession.getAttribute("firstname"));
If you want to make sure it is the case, you can do:
assertNotNull(mockSession.getAttribute("firstname"));
before you fire the GET request.

Resources