How to test DELETE method in Spring boot using Mockito and JUnit - java

In Spring boot framework, I'm finding a difficulty with the controller Unit testing using JUnit and Mockito. I want to test this method. How to test DELETE Request method:
// delete application
Controller class
#DeleteMapping("/applications")
public String deleteApplicationByObject(#RequestBody Application application) {
applicationService.deleteById(application.getId());
return "Deleted";
}
// delete application
Service class
#Override
#Transactional
public String removeById(Long id) {
dao.deleteById(id);
return "SUCCESS";
}
// delete application
Dao class
#Override
public void deleteById(Long id) {
Application application = findById(id);
em.remove(application);
}
Thank you in advance.

After a while i'm able to find a solution of my question which is,
ApplicationControllerTest.class
package com.spring.addapplication.test.controller;
import static org.mockito.MockitoAnnotations.initMocks;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.spring.addapplication.controller.ApplicationController;
import com.spring.addapplication.model.Application;
import com.spring.addapplication.service.ApplicationService;
import com.spring.addapplication.url.UrlChecker;
#RunWith(SpringJUnit4ClassRunner.class)
public class ApplicationControllerTest {
#Mock
ApplicationService applicationService;
private MockMvc mockMvc;
#Before
public void setUp() throws Exception {
initMocks(this);// this is needed for inititalization of mocks, if you use #Mock
ApplicationController controller = new ApplicationController(applicationService,urlChecker);
mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
#Test
public void deleteApplication() throws Exception {
Mockito.when(applicationService.removeById(10001L)).thenReturn("SUCCESS");
mockMvc.perform(MockMvcRequestBuilders.delete("/applications", 10001L))
.andExpect(status().isOk());
}

Related

NullPointer Mocking Kafka Results

I am writing tests and I was looking to mock the result of the kafka admin client, when a topic is created.
I am using Mockito to write my unit tests.
Here is the test code:
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ExecutionException;
import org.apache.kafka.clients.admin.Admin;
import org.apache.kafka.clients.admin.CreateTopicsResult;
import org.apache.kafka.clients.admin.ListTopicsResult;
import org.apache.kafka.common.KafkaFuture;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.Mock;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.junit.main.Launch;
import io.restassured.RestAssured;
import io.restassured.filter.log.RequestLoggingFilter;
import io.restassured.filter.log.ResponseLoggingFilter;
#QuarkusTest
public class AppTest {
#InjectMocks
private App mockApp;
#Mock
private Client mockClient;
#Mock
private Database mockDatabase;
#Mock
private Admin mockKafkaAdmin;
#Mock
private ListTopicsResult mockListTopicResult;
#Mock
private KafkaFuture<Set<String>> mockKafkaFuture;
#Mock
private KafkaFuture<Void> mockKafkaFutureVoid;
#Mock
private Set<String> mockSet;
#Mock
private CreateTopicsResult mockCreateTopicResult;
#Mock
private Map<String, KafkaFuture<Void>> mockKafkaTopicResult;
#BeforeAll
public static void setupAll() {
RestAssured.filters(new RequestLoggingFilter(), new ResponseLoggingFilter());
}
#BeforeEach
public void setUp() {
MockitoAnnotations.openMocks(this);
}
#Test
#Launch(value = {}, exitCode = 1)
public void testLaunchCommandFailed() {}
#Test
public void testCreateTopic() throws InterruptedException, ExecutionException {
Mockito.when(mockClient.getKafka()).thenReturn(mockKafkaAdmin);
Mockito.when(mockClient.getKafka().createTopics(Mockito.anyList())).thenReturn(mockCreateTopicResult);
Mockito.when(mockCreateTopicResult.values()).thenReturn(mockKafkaTopicResult);
Mockito.when(mockKafkaTopicResult.get("meme.transmit.test")).thenReturn(mockKafkaFutureVoid);
mockApp.createTopic("test");
Mockito.when(mockClient.getKafka().listTopics()).thenReturn(mockListTopicResult);
Mockito.when(mockClient.getKafka().listTopics().names()).thenReturn(mockKafkaFuture);
Mockito.when(mockClient.getKafka().listTopics().names().get()).thenReturn(mockSet);
Assertions.assertTrue(mockApp.containsTopic("test"));
}
// ...
}
I get a nullpointer error when this line is called in the production code:
Mockito.when(mockCreateTopicResult.values()).thenReturn(mockKafkaTopicResult);
But as you can see I mocked it with mockKafkaTopicResult. What might I be missing here? Also is there an easier method to work with KafkaAdminClient when writing unit tests?
Mockito.when(mockClient.getKafka().createTopics(Mockito.anyList()))
.thenReturn(mockCreateTopicResult);
The issue was that I was using anyList(), when the createTopics() only accepts Collections.
The fix: Mockito.anyCollections()

Spring Boot Unit Test returns 404 instead of 200

I am new in springboot. I am just watching the Spring in Action and programming follow the author.
then things get difficult when i just reading the chapter 1. I need to test a controller. the code in this book is:
package tacos;
import static org.hamcrest.Matchers.containsString;
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;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
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.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
#RunWith(SpringRunner.class)
#WebMvcTest(HomeController.class) // <1>
public class HomeControllerTest {
#Autowired
private MockMvc mockMvc; // <2>
#Test
public void testHomePage() throws Exception {
mockMvc.perform(get("/")) // <3>
.andExpect(status().isOk()) // <4>
.andExpect(view().name("home")) // <5>
.andExpect(content().string( // <6>
containsString("Welcome to...")));
}
}
I am using springboot 2.7.3 so i just remove #RunWith(SpringRunner.class) from my code. and i immediately get an error when do the test:
after google that i realized it might not find my controller so I add #Import(HomeController.class) to the test class. It looks like:
package com.qph.tacos;
import org.hamcrest.Matchers;
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.context.annotation.Import;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
#WebMvcTest(HomeControllerTest.class)
#Import(HomeController.class)
public class HomeControllerTest {
#Autowired
private MockMvc mockMvc;
#Test
public void testHomePage() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.view().name("home"))
.andExpect(MockMvcResultMatchers.content().string(Matchers.containsString("Welcome to...")));
}
}
then it just pass the test!!!
now i just wonder why the code written by the author can pass the test without #Import(HomeController.class)?
my directory structure is like:
the controller to be tested is:
package com.qph.tacos;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
#Controller
public class HomeController {
#GetMapping("/")
public String home() {
// return the name of template
return "home";
}
}
I am new in springboot. maybe it's a simple question but i really spent so much time on it.
Thanks for your help!
Change to
#WebMvcTest(HomeController.class)
You should reference the controller under test with this annotation, otherwise it won't be loaded into the application context.

How to write unit test for clear all cache using cache manager

I have a method that evicts all the caches. PFB code for same:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;
import com.admin.AdminResponse;
#Service
public class CachingService {
private final static Logger logger = LoggerFactory.getLogger(CachingService.class);
#Autowired
protected CacheManager cacheManager;
public AdminResponse evictAllCaches() {
logger.info("Start - Clearing of cache");
cacheManager.getCacheNames().parallelStream()
.forEach(cacheName -> cacheManager.getCache(cacheName).clear());
AdminResponse adminResponse = new AdminResponse();
adminResponse.setMessage("ok");
logger.info("End - Clearing of cache");
return adminResponse;
}
}
Below is the unit test I'm trying to write:
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import com.admin.AdminResponse;
#ExtendWith(SpringExtension.class)
public class CachingServiceTest {
#InjectMocks
private CachingService testCachingService;
#Mock
protected CacheManager cacheManager;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testEvictAllCaches() {
AdminResponse adminResponse = testCachingService.evictAllCaches();
assertEquals("ok", adminResponse.getMessage());
}
}
I'm unable to understand how to write unit tests for code
cacheManager.getCacheNames().parallelStream()
.forEach(cacheName -> cacheManager.getCache(cacheName).clear());
Can someone please help? Thank you for your time!
You can write test code for Cache as follow:
#Test
public void testEvictAllCaches() {
Cache cache = Mockito.mock(Cache.class);
when(cacheManager.getCacheNames()).thenReturn(List.of("cacheName1", "cacheName2"));
Mockito.when(cacheManager.getCache(anyString())).thenReturn(cache);
AdminResponse adminResponse = testCachingService.evictAllCaches();
assertEquals("ok", adminResponse.getMessage());
}

NullPointerException in injectedMock

I have a RestController that I want to test:
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class PetController implements PetApi {
#Autowired
PetRepository pr;
#Override
public ResponseEntity<Pet> addPet(#Valid Pet pet) {
pr.save(new PetBE(9L, "dummy"));
return new ResponseEntity<Pet>(pet, HttpStatus.OK);
}
}
import org.springframework.data.repository.CrudRepository;
public interface PetRepository extends CrudRepository<PetBE, Long> {
}
I want to mock PetRepository and test if the object passed is the object returned:
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import com.example.petstore.backend.api.model.Pet;
import com.example.petstore.backend.db.PetRepository;
import com.example.petstore.backend.db.PetBE;
import static org.mockito.Mockito.when;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.AdditionalAnswers.returnsFirstArg;
#SpringBootTest
public class PetControllerTest {
#InjectMocks
private PetController petController;
#MockBean
private PetRepository pr;
#Test
void testAddPet() {
when(pr.save(any(PetBE.class))).then(returnsFirstArg());
Pet p1 = new Pet().id(5L).name("Klaus");
assertNotNull(petController);
/*L35*/ ResponseEntity<Pet> r = petController.addPet(p1);
assertEquals(new ResponseEntity<Pet>(p1, HttpStatus.OK), r);
}
}
When I run this method as a gradle test, I get
com.example.petstore.backend.api.implementation.PetControllerTest > testAddPet() FAILED
java.lang.NullPointerException at PetControllerTest.java:35
which is petController.addPet(p1);.
My printlns in addPet are not displayed and I can't set any breakpoints there because it is mocked. The only reference in addPet that could be null is pr, but it works fine when I send a request with curl.
I've also tried adding
#BeforeAll
public void setup() {
MockitoAnnotations.initMocks(this);
}
because it was suggested here but that gave an InitializationException:
com.example.petstore.backend.api.implementation.PetControllerTest > initializationError FAILED
org.junit.platform.commons.JUnitException at LifecycleMethodUtils.java:57
How can I debug this?
How can I get this to work?
You're mixing annotations from various testing frameworks here. If you wish to use the Mockito annotation #InjectMocks then I'd recommend not using any Spring-related mocking annotations at all, but rather the #Mock annotation to create a mocked version of the bean you want to inject (into the #InjectMocks-annotated field). Also make sure you bootstrap the Mockito extension with #ExtendWith(MockitoExtension.class). Something like:
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import com.example.petstore.backend.api.model.Pet;
import com.example.petstore.backend.db.PetRepository;
import com.example.petstore.backend.db.PetBE;
import static org.mockito.Mockito.when;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.AdditionalAnswers.returnsFirstArg;
#ExtendWith(MockitoExtension.class)
public class PetControllerTest {
#InjectMocks
private PetController petController;
#Mock
private PetRepository pr;
#Test
void testAddPet() {
when(pr.save(any(PetBE.class))).then(returnsFirstArg());
Pet p1 = new Pet().id(5L).name("Klaus");
assertNotNull(petController);
ResponseEntity<Pet> r = petController.addPet(p1);
assertEquals(new ResponseEntity<Pet>(p1, HttpStatus.OK), r);
}
}
EDIT: Calling MockitoAnnotations.initMocks(this) inside for example a #BeforeEach-annotated method is necessary if you don't want to use the MockitoExtension. They're essentially the same thing, but it's less necessary in JUnit Jupiter because you can extend a test class with multiple extensions, which was not possible in JUnit 4.x. So if you wanted to bootstrap your test with both a Spring context and Mockito, then you had to pick one of them and setup the other one yourself.

NoClassDefFoundError: org/springframework/web/bind/MissingMatrixVariableException -- testing repositories/interfaces

Here's the problem: I keep running into the MissingMatrixVariableException in my stacktrace when attempting to test my Repository interfaces. I've got 5 and want to increase my overall code coverage.
Be nice - I'm a noob. I've attempted to Mock after doing my own research, and it's been a bit overwhelming.
I've tried Mocking the repository and instantiated my MockMvc mockMvc variables. I've setUp the MockitoAnnotations.initMocks(this);
I run the test and for any testing I've done, I've hit the MissingMatrixVariableException error.
I've found nothing in Stack / Google searches for this Exception when testing repositories.
package example.repository;
import example.model.Metrics;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
#EnableJpaRepositories
public interface MetricsRepository extends JpaRepository<Metrics, Long> {
List<Metrics>findByDate(String date);
#Modifying
#Transactional
#Query(nativeQuery = true, value = "delete from backlogreport.metrics where date = ?1")
void deleteDate(String date);
}
This is my test class:
package example.repository;
import example.controller.RestApiController;
import example.model.Metrics;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.test.web.servlet.setup.StandaloneMockMvcBuilder;
import java.util.Collections;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
public class MetricsRepositoryTest {
#InjectMocks
private RestApiController restApiController;
#Mock
private MetricsRepository MetricsRepository;
private MockMvc mockMvc;
#Before
public void setUp(){
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(restApiController).build();
}
#Test
public void shouldGetByDate() throws Exception {
Metrics Metrics = new Metrics();
Metrics.setDate("2019-04-01");
Metrics.setAgeLength("20 days old");
when(MetricsRepository.findAll())
.thenReturn(Collections.singletonList(Metrics));
mockMvc.perform(get("/report/2019-04-01"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(print());
}
}
What I'm trying to achieve is when the mockMvc is setup, I put in the date which accepts a String ("2019-04-01") and an age length of ("20 Days").
I then perform my urL "get" and expect the status is ok, then print... except I keep hitting this MissingMatrixVariableException. Any ideas?

Categories

Resources