Spring controller tests with mocks - spring

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.

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;

Spring Boot - unit test not detecting the controller test

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.

#Autowired not working inside testcontainers

I am using test containers to make integration tests with the MSSQLServer image and when I am trying to inject my repository I am recieving the following error:
lateinit property modelRepository has not been initialized
And this confuse me because I'm using the same path I used to create the test but using a postgress database in another project.
My test archive:
package *.models.integration
import *.portadapter.repository.ModelRepository
import *.builders.ModelBuilder
import org.junit.ClassRule
import org.junit.Test
import org.junit.jupiter.api.Assertions.assertEquals
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
import org.springframework.test.context.DynamicPropertyRegistry
import org.springframework.test.context.DynamicPropertySource
import org.testcontainers.containers.MSSQLServerContainer
import org.testcontainers.containers.startupcheck.MinimumDurationRunningStartupCheckStrategy
import org.testcontainers.junit.jupiter.Testcontainers
import java.time.Duration
import java.util.function.Supplier
#DataJpaTest
#Testcontainers
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class ModelRepositoryTest {
#Autowired
private lateinit var modelRepository: ModelRepository
companion object {
private val hibernateDriver: Supplier<Any> = Supplier { "org.hibernate.dialect.SQLServerDialect" }
private val hibernateDll: Supplier<Any> = Supplier { "none" }
#ClassRule
#JvmField
val mssqlserver: MSSQLServerContainer<*> = MSSQLServerContainer("mcr.microsoft.com/mssql/server:2017-latest")
.withStartupCheckStrategy(MinimumDurationRunningStartupCheckStrategy(Duration.ofSeconds(5)))
.acceptLicense()
#JvmStatic
#DynamicPropertySource
fun properties(registry: DynamicPropertyRegistry) {
registry.add("spring.datasource.url", mssqlserver::getJdbcUrl)
registry.add("spring.datasource.username", mssqlserver::getUsername)
registry.add("spring.datasource.password", mssqlserver::getPassword)
registry.add("spring.jpa.properties.hibernate.dialect", hibernateDriver)
registry.add("spring.jpa.hibernate.ddl-auto", hibernateDll)
mssqlserver.acceptLicense().start()
}
}
#Test
fun `it should save a model`() {
val model = ModelBuilder().createModel().get()
modelRepository.save(model)
val modelFound = modelRepository.findByCode(model.code)
assertEquals(model.code, modelFound.get().code)
}
}
My Repository:
package *.portadapter.repository
import *.model.domain.Model
import org.springframework.data.jpa.repository.JpaRepository
import java.util.*
interface ModelRepository: JpaRepository<Model, String> {
fun findByCode(code: String): Optional<Model>
}
Could anyone please help me
Make sure you are using the right classes from junit4 or junit5. If you are using junit4 then add #RunWith(SpringRunner.class)
As I mentioned in the comment above, imports from junit4 and junit5 are mixed in the test provided. Below you can find the examples
junit4
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.jdbc.DataJdbcTest;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.test.context.junit4.SpringRunner;
import org.testcontainers.containers.MSSQLServerContainer;
import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
#RunWith(SpringRunner.class)
#DataJdbcTest
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
public class SqlserverDemoApplication3Tests {
#ClassRule
public static MSSQLServerContainer sqlserver = new MSSQLServerContainer("mcr.microsoft.com/mssql/server:2017-CU12")
.acceptLicense();
#DynamicPropertySource
static void sqlserverProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", sqlserver::getJdbcUrl);
registry.add("spring.datasource.username", sqlserver::getUsername);
registry.add("spring.datasource.password", sqlserver::getPassword);
}
#Autowired
private JdbcTemplate jdbcTemplate;
#Test
public void contextLoads() {
this.jdbcTemplate.update("insert into profile (name) values ('profile-1')");
List<Map<String, Object>> records = this.jdbcTemplate.queryForList("select * from profile");
assertThat(records).hasSize(1);
}
}
junit5
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.jdbc.DataJdbcTest;
import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.MSSQLServerContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import java.util.List;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
#Testcontainers
#DataJdbcTest
#AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
class SqlserverDemoApplication2Tests {
#Container
private static MSSQLServerContainer sqlserver = new MSSQLServerContainer("mcr.microsoft.com/mssql/server:2017-CU12")
.acceptLicense();
#DynamicPropertySource
static void sqlserverProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", sqlserver::getJdbcUrl);
registry.add("spring.datasource.username", sqlserver::getUsername);
registry.add("spring.datasource.password", sqlserver::getPassword);
}
#Autowired
private JdbcTemplate jdbcTemplate;
#Test
void contextLoads() {
this.jdbcTemplate.update("insert into profile (name) values ('profile-1')");
List<Map<String, Object>> records = this.jdbcTemplate.queryForList("select * from profile");
assertThat(records).hasSize(1);
}
}

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);
}
}

Testing connectiong with db, tests passes but no new instance in db created

What I wan to do: I want to test if my app is connecting correctly with db. In order to do so I was using these tutorials: http://www.baeldung.com/spring-boot-testing http://www.baeldung.com/spring-testing-separate-data-source So I'm creating new testUser, saving it and checking if user found by userName is equal to the one I've saved.
What is not working: even though the test passes, no new user appears in database. I don't know why. Any suggestions?
Test:
package com.shareabook.integration.user;
import com.shareabook.constants.initialNumberOfPoints;
import com.shareabook.model.Points;
import com.shareabook.model.User;
import com.shareabook.repository.PointsRepository;
import com.shareabook.repository.RoleRepository;
import com.shareabook.repository.UserRepository;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Arrays;
import static org.assertj.core.api.Assertions.assertThat;
#RunWith(SpringRunner.class)
#DataJpaTest
public class userTest {
#Autowired
private UserRepository userRepository;
#Autowired
private RoleRepository roleRepository;
#Autowired
private PointsRepository pointsRepository;
private BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
#Test
public void whenFindByUserName_thenReturnUser() {
//given
User testUser = new User();
// Creates new points instance
Points points = new Points();
points.setAmountOfPoints(initialNumberOfPoints.INITIAL_NUMBER_OF_POINTS.getInitialNumberOfPoints());
pointsRepository.save(points);
int tempId = points.getId();
testUser.setUserName("userName");
testUser.setFirstName("firstName");
testUser.setLastName("lastName");
testUser.setPassword(passwordEncoder.encode("P#ssword123"));
testUser.setEmail("emal#email.com");
testUser.setIsBlocked(false);
testUser.setIdpoints(tempId);
testUser.setRoles(Arrays.asList(roleRepository.findByRole("USER")));
userRepository.save(testUser);
//when
User found = userRepository.findByUserName(testUser.getUserName());
//then
assertThat(found.getUserName()).isEqualTo(testUser.getUserName());
}
}
------EDIT---------
After helpful suggestions in comments I changed my test a bit and now it's working as expected.
package com.shareabook.integration.user;
import com.shareabook.constants.initialNumberOfPoints;
import com.shareabook.model.Points;
import com.shareabook.model.User;
import com.shareabook.repository.PointsRepository;
import com.shareabook.repository.RoleRepository;
import com.shareabook.repository.UserRepository;
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.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
#RunWith(SpringRunner.class)
#SpringBootTest
public class userTest {
#Autowired
private UserRepository userRepository;
#Autowired
private RoleRepository roleRepository;
#Autowired
private PointsRepository pointsRepository;
private BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
#Test
public void whenFindByUserName_thenReturnUser() {
//given
User testUser = new User();
// Creates new points instance
Points points = new Points();
points.setAmountOfPoints(initialNumberOfPoints.INITIAL_NUMBER_OF_POINTS.getInitialNumberOfPoints());
pointsRepository.save(points);
int tempId = points.getId();
testUser.setUserName("userName");
testUser.setFirstName("firstName");
testUser.setLastName("lastName");
testUser.setPassword(passwordEncoder.encode("P#ssword123"));
testUser.setEmail("emal#email.com");
testUser.setIsBlocked(false);
testUser.setIdpoints(tempId);
testUser.setRoles(Arrays.asList(roleRepository.findByRole("USER")));
userRepository.save(testUser);
//when
User found = userRepository.findByUserName(testUser.getUserName());
//then
assertNotNull(found);
assertEquals(testUser.getUserName(), found.getUserName());
}
}
#DataJpaTest will configure an in-memory embedded database, scan for #Entity classes and configure Spring Data JPA repositories.
It is transactional but will rollback at the end of each test!
That's why you don't have data in your database.

Resources