I don't know how to create the unit test for my controller with Delete Method.
//Controller class
#PostMapping("delete")
public ResponseEntity<Void> deleteClient(#RequestBody DeleteClientModel deleteClientModel){
clientService.deleteClientById(deleteClientModel.getId());
return new ResponseEntity<>(HttpStatus.OK);
}
//Service class
public void deleteClientById(int id) {
clientRepository.deleteById(id);
}
As you can see the method doesn't return anything so that's why I don't know how to test the controller class. Please help me
Here's a test
#Test
public void ClientController_deleteClient() throws Exception{
???
}
You can use MockMvcRequestBuilder to run controller tests in springboot as below
include the gradle dependency,
testCompile('org.springframework.boot:spring-boot-starter-test')
#WebMvcTest(ClientController.class)
public class TestClientController {
#Autowired
private MockMvc mvc;
#Test
public void ClientController_deleteClient() throws Exception
{
DeleteClientModel deleteClientModel = new DeleteClientModel();
deleteClientModel.setId("100");
mvc.perform( MockMvcRequestBuilders
.post("/delete")
.content(asJsonString(deleteClientModel))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
}
public static String asJsonString(final Object obj) {
try {
return new ObjectMapper().writeValueAsString(obj);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Hope this helped :)
Related
I've made rest controller, that calls #service class:
#Service
public class UnitServiceImpl extends HttpRequestServiceImpl implements UnitService {
#Override
public Unit addUnit(String unitName) {
final Unit unit = new Unit();
unit.setUnitName(unitName);
return unitRepository.save(unit);
}
#Override
public Unit getUnit(int id) {
final Unit unit = unitRepository.findById(id);
if (unit == null) {
throw new EntityNotFoundException("Unit is not found");
}
return unit;
}
#Override
public Iterable<Unit> getAllUnits() {
return unitRepository.findAll();
}
}
EnityNotFoundException is handled by ExceptionHandlingController:
#RestController
#ControllerAdvice
public class ExceptionHandlingController extends ResponseEntityExceptionHandler {
#ExceptionHandler({RuntimeException.class})
public final ResponseEntity<ErrorDetails> handleRuntimeException(RuntimeException ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails(new Date(), ex.getMessage(),
request.getDescription(false));
HttpStatus httpStatus = HttpStatus.BAD_REQUEST;
if (ex.getClass() == EntityNotFoundException.class) {
httpStatus = HttpStatus.NOT_FOUND;
}
return new ResponseEntity<>(errorDetails, httpStatus);
}
}
Unit controller just calls the getUnit:
#RestController
public class UnitController {
private final UnitService managementService;
#PostMapping(value = "/unit", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Unit> addUnit(HttpServletRequest request) throws FieldsIsAbsentException {
final String unitName = managementService.getParameter(request, "unit_name");
final Unit unit = managementService.addUnit(unitName);
return new ResponseEntity<>(unit, HttpStatus.CREATED);
}
public UnitController(UnitService managementService) {
this.managementService = managementService;
}
#GetMapping(value = "/unit", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Iterable<Unit>> getAllUnits() {
final Iterable<Unit> allUnits = managementService.getAllUnits();
return new ResponseEntity<>(allUnits, HttpStatus.OK);
}
#GetMapping(value = "/unit/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Unit> getUnitById(#PathVariable("id") int id) {
final Unit unit = managementService.getUnit(id);
return new ResponseEntity<>(unit, HttpStatus.CREATED);
}
}
Now I need to test them, and created unit test method, that must to check on 404 error:
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#ContextConfiguration
class UnitControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
UnitService unitService;
#MockBean
UnitRepository unitRepository;
#Autowired
private UnitController unitController;
private List<Unit> units;
#Before
public void initUnits() {
units = new ArrayList<>();
Unit unitWithName = new Unit();
unitWithName.setId(1);
unitWithName.setUnitName("NameUnit");
units.add(unitWithName);
Unit unitWithoutName = new Unit();
unitWithoutName.setId(2);
units.add(unitWithoutName);
}
#Test
void contextLoads() {
Assert.assertNotNull(unitController);
}
#Test
void testGetAllUnits() throws Exception {
given(this.unitService.getAllUnits()).willReturn(units);
mockMvc.perform(get("/unit"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON));
}
#Test
void testUnitNotFound() throws Exception {
int id = -1;
given(this.unitRepository.findById(id)).willReturn(null);
mockMvc.perform(get("/unit/-1"))
.andExpect(status().isNotFound())
.andExpect(content().contentType(MediaType.APPLICATION_JSON));
}
}
When I run tests, testGetAllUnits fails:
java.lang.AssertionError: Content type not set
and testUnitNotFound fails with error:
java.lang.AssertionError: Status expected:<404> but was:<201>
But when I remove
#MockBean
UnitService unitService;
It will be working. What the problem?
UPDATE:
I have the similar problem now. This code inserts into database info about unit. But I made mock for the method.
#Test
void testAddUnit() throws Exception {
Unit unit = new Unit();
unit.setId(1);
unit.setUnitName("TestUnit");
given(unitService.addUnit("TestUnit")).willReturn(unit);
mockMvc.perform(post("/unit").param("unit_name", "TestUnit"))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.unitName").value("TestUnit"))
.andExpect(jsonPath("$.id").value(1));
}
You're mocking the wrong bean. The bean throwing the exception is the service bean, so mock that.
#Test
void testUnitNotFound() throws Exception {
int id = -1;
given(this.service.getUnit(id)).willThrow(new EntityNotFoundException("Unit is not found"));
mockMvc.perform(get("/unit/-1"))
.andExpect(status().isNotFound())
.andExpect(content().contentType(MediaType.APPLICATION_JSON));
}
The problem with the testUnitNotFound() test not working is that you are expecting something from the mocked repository to happen inside a service which is also mocked.
If the service is mocked, then no implementation is invoked. Only a default value is returned which is null. And therefore no exception is thrown as expected...
If you want to have the flexibility of having most of the service mocked but having rest of them having their original implementations called, then you should change the:
#MockBean
UnitService unitService;
into
#SpyBean
UnitService unitService;
I am trying to mock a method of a private field that has a return type of void. In my test, I am trying to mock aClass.doSomething() to throw an IllegalStateException and I need to verify that recover() is called. Here is an example:
public class ClassToTest implements Runnable {
private ClassToMock aClass;
#Override
public void run() {
try{
aClass.doSomething("some parameter");
} catch(IllegalStateException e) {
logger.error("Something bad happened", e);
recover();
}
}
public void recover(){
logger.info("I am recovering");
}
}
I have done each piece separately:
Mock a method call of a private field
Mock a method that has void return type
Throw exception
Verify a private method call
but I wasn't able to put all together. Any help is appreciated
I thought I'd elaborate GhostCat's comments:
Stay with Mockito
Mockito is more than a mocking framework - it's a discipline. If you read carefully the documentation for Mockito and restrain yourself from resorting to PowerMock et al you will learn good OOP practice.
Read how to do dependency injection with constructors
Primum non nocere - first refactor your code like this:
public class ClassToTest implements Runnable {
private final ClassToMock aClass;
private final Logger logger;
//injection of collaborators through the constructor
public ClassToTest(ClassToMock aClass, Logger logger) {
this.aClass = aClass;
this.logger = logger;
}
#Override
public void run() {
try{
aClass.doSomething("some parameter");
} catch(IllegalStateException e) {
logger.error("Something bad happened", e);
recover();
}
}
public void recover() { //there is no need for this method to be public - see Effective Java item 13
logger.info("I am recovering");
}
}
Now your code is testable using Mockito without resorting to more complex mocking frameworks:
//mocks
#Mock ClassToMock classToMock;
#Mock Logger mockLogger;
//system under test
ClassToTest classToTest;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks();
classToTest = new ClassToTest(classToMock, mockLogger);
}
#Test
public void whenRun_thenDoesSomethingWithSomeParameter() {
//act
classToTest.run();
//assert
verify(classToMock).doSomething(eq("some parameter"));
}
#Test
public void givenAnIllegalStateForAClass_whenRun_thenLogsError() {
//arrange
IllegalStateException e = new IllegalStateException();
when(classToMock.doSomething(anyString()).thenThrow(e);
//act
classToTest.run();
//assert
verify(mockLogger).error(eq("Something bad happened"), same(e));
}
#Test
public void givenAnIllegalStateForAClass_whenRun_thenLogsRecovery() {
//arrange
when(classToMock.doSomething(anyString()).thenThrow(new IllegalStateException());
//act
classToTest.run();
//assert
verify(mockLogger).info(eq("I am recovering"));
}
I am new to Junit world,please let me know for below issue what might be the case
even though i missing ;(semicolon) test case are being passed successfully
Please look below code snippet
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = DataBaseConfig.class)
#WebAppConfiguration
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
#Ignore
public class BlogTest {
#PersistenceContext
private EntityManager entityManager;
#Autowired
private Blog blogManager;
#Test
public void test() {
fail("Not yet implemented");
}
#Before
public void before() {
Session session = Utils.getSessionFromEntityManger(entityManager);
}
#Test
public void addBlogTest() {
try {
LoggedInUser loggedInUser = new LoggedInUser();
loggedInUser.setTenantOID(1);
loggedInUser.setUserID(1);
loggedInUser.setSessionId("Sadasdas");
Blog blog = new Blog();
blog.setBlogName("WindowsTALKEE");
blog.setCreatedByID(1);
blogManager.addBlog(blog, loggedInUser);
System.out.println("Successfully inserted");
} catch (Exception e) {
e.printStackTrace();
}
}
}
Delete the #Ignore.
#Ignore ignores the whole test class.
http://junit.sourceforge.net/javadoc/org/junit/Ignore.html
I'm new to Testing side.I'm using Spring Mvc in my application. I followed some tutorials to write for controller and service Test Case. I'm facing error in service test. Please help !
Service :
#Autowired
private PatientDao patientDao;
#Autowired
private PrefixDao prefixDao;
public Patient createPatient(Patient patient) throws Exception {
patient.setAgeorDob();
return createPatientInSync(patient);
}
private synchronized Patient createPatientInSync(Patient patient)
throws Exception {
try {
Prefix prefix = prefixDao.getPrefixForType(PrefixType.PATIENT);
patient.setPatientNo(prefix.getPrefixedNumber());
patientDao.createPatient(patient); //SAVE PATIENT
prefixDao.incrementPrefix(prefix);
} catch (ConstraintViolationException ex) {
throw new InternalErrorException("Please enter valid data", ex);
} catch (NullPointerException e) {
e.printStackTrace();
throw new InternalErrorException(
"Please create Prefix for Patient", e);
}
return patient;
}
Service Test case:
#ContextConfiguration(locations = {
"classpath:/applicationContext-resources.xml",
"classpath:/applicationContext-service.xml",
"classpath:/applicationContext-dao.xml",
"classpath:/applicationContext.xml" })
#RunWith(SpringJUnit4ClassRunner.class)
public class PatientServiceTest {
#Autowired
#Mock
private PatientDao patientDao;
#InjectMocks
private PatientServiceImpl patientService = new PatientServiceImpl();
private PrefixDao prefixDao;
#Before
public void doSetup() {
patientDao = mock(PatientDao.class);
prefixDao = mock(PrefixDao.class);
// Mockito.mock(PatientDao.class);
}
#Before
public void initMocks() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testSaveUser() throws Exception {
Patient mockPatient = new Patient();
mockPatient.setFirstName("Aravinth");
mockPatient.setSex(Gender.Male);
mockPatient.setAgeOrDob("24");
Prefix prefix = new Prefix();
prefix.setPrefixType(PrefixType.PATIENT);
prefix.setPrefix("Pat-");
prefix.setSequenceNo(23);
when(prefixDao.getPrefixForType(PrefixType.PATIENT)).thenReturn(prefix);
System.out.println(prefix.getSequenceNo());
mockPatient = patientService.createPatient(mockPatient);
assertEquals("Aravinth", mockPatient.getFirstName());
verify(patientDao, times(1)).createPatient(mockPatient);
}
}
Verify times works fine.I got Nullpointer in assertEquals.
Need to #Mock PrefixDao first.
If you are using Junit 5, no need to run initMocks(this). Otherwise you need this: MockitoAnnotations.initMocks(this);
With that, the mockito will wire two mock Dao objects to your service.
Also I don't see you mock action for patientDao.
When(patientDao.create()).thenReturn(...);
Code:
public class AccountService(){
private ObjectMapper mapper = new ObjectMapper();
public Account getAccount(){
try {
ClientResponse response = RestUtility.getAccounts();
if(CLientResponse.OK.Status == response.getClientResponseStatus()){
return mapper.readValue(response.getEntity(String.class), Account.class)
}
} catch(Exception e){
log.error(e.getMessage(), e);
}
return null;
}
}
How can I mock this service? The RestUtility is a static utility and cannot be mocked by mockito. All I want is for my method to return a list of 'mock' accounts. Is it even possible with this architecture?
To mock statick method you cna use PowerMock.
Or you can create wrapper on your RestUtility class.
Reference to this wrapper should be provided on constructor.
If you change to
public class AccountService() {
protected ClientResponse getResponse() { return RestUtility.getAccounts(); }
public Account getAccount() {
try {
ClientResponse response = getResponse();
...
}
}
it is trivial to mock out getResponse() using Mockito or other mock frameworks. Or even easier:
public class AccountServiceTest {
class TestableAccountService extends AccountService {
#Override
protected ClientResponse getResponse() { return <yourmockresponsegoeshere>; }
}
#Test
public void testMe() {
AccountService ac = new TestableAccountService();
assertThat( ac.getAccount.size() , equalTo( 1 ) );
// etc
...
}
Cheers,