Mockito thenThrow cannot be catch - java

I am using Mockito to mock the method of service layer.
This is my test code.
#InjectMocks
MyServiceImpl myServiceImpl;
#Mock
MyDAO myDAO;
#Rule
public ExpectedException exceptionRule = ExpectedException.none();
#Test
public void getAllFail(){
Mockito.when(myDAO.getAll().thenThrow(new DataException("mock"));
exceptionRule.expect(ServiceException.class);
myServiceImpl.getAllData();
}
service code
#Service
public class myServiceImpl extends myService{
private final MyDAO myDAO;
...
#Override
public List getAllData(){
try{
return myDAO.getAll();
} catch (DataException exception){
throw new ServiceException("exception");
}
}
}
At first I thought that by mocking DAO class to throw exception, it would be caught by catch and turn into ServiceException but the result was
java.lang.AssertionError:
Expected an instance of com.example.exception.ServiceException
but: <com.example.exception.DataException: mock> is a com.example.exception.DataException
How can I test exception of my service in this case? Please guide me. Thank you in advance.

I think you need to use Assertions.assertThrows when you are expecting an exception from a method call and you need chain the exception properly. Here is how I have done it.
Service class with exceptions and method calls
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
#Service
public class SampleTestService {
private final MyDao myDao;
public SampleTestService(MyDao myDao) {
this.myDao = myDao;
}
public List<String> getData() {
try {
return myDao.getStringList();
} catch (MyDao.DataException dataException) {
throw new ServiceException("Error getting data");
}
}
static class ServiceException extends RuntimeException {
public ServiceException(String message) {
super(message);
}
}
}
class MyDao {
public List<String> getStringList() {
return Collections.emptyList();
}
static class DataException extends RuntimeException {
public DataException(String message) {
super(message);
}
}
}
Unit Test class in action
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.util.Arrays;
import java.util.List;
#ExtendWith(SpringExtension.class)
class SampleTestServiceTest {
// private final MyDao myDao = mock(MyDao.class);
#Mock
MyDao myDao;
#Test
void testDaoThrowsException() {
Mockito.when(myDao.getStringList()).thenThrow(new MyDao.DataException("Error connecting to database"));
SampleTestService sampleTestService = new SampleTestService(myDao);
Assertions.assertThrows(SampleTestService.ServiceException.class,
() -> {
sampleTestService.getData();
});
}
#Test
void testDaoReturnData() {
List<String> colors = Arrays.asList("red", "green", "blue");
Mockito.when(myDao.getStringList()).thenReturn(colors);
SampleTestService sampleTestService = new SampleTestService(myDao);
List<String> data = sampleTestService.getData();
Assertions.assertEquals(3, data.size());
Assertions.assertSame(data, colors);
}
}

Related

How to write Junit Test Cases in springBoot?

Thid is my mapping from my controller class , now I want to write unit test case for the same
#GetMapping(value = "/tokenSearch/{id}/{name}/{values}/{data_name}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> getValuesfromToken(
throws ClientProtocolException, IOException, ParseException {
ResponseEntity<String> data = elasticService.getData();
return data;
}
this is what I was trying but its asking for castargument for Result matcher, getting error , can someone pls help me with this
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
#AutoConfigureMockMvc
public class ElasticCaseTests extends Mockito {
#Autowired
private MockMvc mockMvc;
#Test
public void testGetValuesfromToken() throws Exception {
String contentAsString = mockMvc.perform(get("/tokenSearch/1/PRODUCT/PRODUCT/189")).andExpect(status().isOk())
.andExpect(jsonPath("$.id", is("1"))).andExpect(jsonPath("$.name", is("product")))
.andExpect(jsonPath("$.values", is("product")))
.andExpect(jsonPath("$.searching_word", is("189"))).andExpect(status().isOk()).andReturn().getResponse()
.getContentAsString();
}
java.lang.AssertionError: No value at JSON path "$.id"' , can someone help me with this
This could be one example:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
#AutoConfigureMockMvc
class ControllerTest {
#Autowired
private MockMvc mockMvc;
#Test
void testGetValuesfromToken() throws Exception {
this.mockMvc
.perform(get("/tokenSearch/............."))
.andExpect(status().isOk())
.andExpect(jsonPath("$.hierarchy_name"").value(".....what you expect..."))
.andDo(print());
}
See example it may help
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import ….services.AuthorizationService;
import ….AuthorizationRequest;
import ….AuthorizationResponse;
import java.time.Clock;
import java.time.Instant;
import java.time.ZoneId;
import org.junit.Before;
import org.junit.Test;
public class MyControllerTest {
AuthorizationService authorizationService;
AuthorizationController controller;
private Clock clock;
#Before
public void setUp() throws Exception {
clock = Clock.fixed(Instant.now(), ZoneId.systemDefault());
authorizationService = mock(AuthorizationService.class);
controller = new AuthorizationController(authorizationService);
}
#Test
public void createJws() throws Exception {
when(authorizationService.createJws(any(AuthorizationRequest.class)))
.thenReturn(new AuthorizationResponse());
AuthorizationRequest authorizationRequest =
AuthorizationRequest.builder().id(“abc”).build();
AuthorizationResponse jwsResponse =
controller.createJws(authorizationRequest);
verify(authorizationService).createJws(authorizationRequest);
}
}
I usually write my Controller tests more or less like this. If you want to test the json output and status correctness, you could implement a helper method like asJsonString and see if everything is proper. Maybe you find this approach helpful.
#WebMvcTest
#ContextConfiguration(classes = {ResourceController.class})
class ResourceControllerTest {
private final String JSON_CONTENT_TYPE = "application/json";
#Autowired
private MockMvc mockMvc;
#MockBean
private ElasticService elasticService;
#Test
public void shouldReturnProperData() throws Exception {
String data = "some returned data"; // format it properly, as elasticService would
YourJsonObject objectToReturn = new YourJsonObject(...);
when(elasticService.getData()).thenReturn(data);
mockMvc.perform(post("/tokenSearch/1/PRODUCT/PRODUCT/189").contentType(JSON_CONTENT_TYPE).content(asJsonString(email)))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string(asJsonString(objectToReturn)));
}
}
private String asJsonString(final Object obj) {
try {
return new ObjectMapper().writeValueAsString(obj);
} catch (Exception e) {
throw new RuntimeException(e); // delete this exception conversion if you will :)
}
}
}
The most important is though to test if elasticService returns the proper data so you can implement the unit tests there. Here, you can test statuses, paths, and slightly the json outlook, but these are not any kind of amazing tests.

How to test function returning Mono<Void> which has another Mono<T> within using Reactor's StepVerifier

I have a ServiceWebClientInterface.java like this
import reactor.core.publisher.Mono;
public interface ServiceWebClientInterface {
Mono<String> apiCall();
}
MyClass.java
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
public class MyClass extends AbstractGatewayFilterFactory<MyClass.Config> {
private final ServiceWebClientInterface serviceWebClientInterface;
MyClass(final ServiceWebClientInterface serviceWebClientInterface) {
this.serviceWebClientInterface = serviceWebClientInterface;
}
#Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
return serviceWebClientInterface.apiCall().flatMap(response -> {
if (!"Valid".equals(response)) {
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
});
};
}
public static class Config {
// Put the configuration properties
}
}
I'm trying to unit test myMethod using StepVerifier, but I am not able to execute statements inside the inner lambda function of myMethod.
MyClassTest.java
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;
class MyClassTest {
#Mock
ServiceWebClientInterface mockServiceWebClientInterface;
#Mock
private ServerWebExchange mockServerWebExchange;
#Mock
private GatewayFilterChain mockGatewayFilterChain;
#Mock
private ServerHttpResponse mockServerHttpResponse;
#BeforeEach
void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
void test_apply_forValid() {
when(mockServiceWebClientInterface.apiCall()).thenReturn(Mono.just("Valid"));
MyClass.Config config = new MyClass.Config();
MyClass myClass = new MyClass(mockServiceWebClientInterface);
GatewayFilter gatewayFilter = myClass.apply(config);
Mono<Void> response = gatewayFilter.filter(mockServerWebExchange, mockGatewayFilterChain);
StepVerifier.create(response).expectComplete();
verify(mockServiceWebClientInterface).apiCall();
verify(mockGatewayFilterChain).filter(mockServerWebExchange);
}
#Test
void test_apply_forInValid() {
when(mockServiceWebClientInterface.apiCall()).thenReturn(Mono.just("InValid"));
when(mockServerWebExchange.getResponse()).thenReturn(mockServerHttpResponse);
MyClass.Config config = new MyClass.Config();
MyClass myClass = new MyClass(mockServiceWebClientInterface);
GatewayFilter gatewayFilter = myClass.apply(config);
Mono<Void> response = gatewayFilter.filter(mockServerWebExchange, mockGatewayFilterChain);
StepVerifier.create(response).expectComplete();
verify(mockServiceWebClientInterface).apiCall();
verify(mockServerHttpResponse).setStatusCode(eq(HttpStatus.FORBIDDEN));
verify(mockServerHttpResponse).setComplete();
verify(mockGatewayFilterChain, never()).filter(mockServerWebExchange);
}
}
Please find the complete code above, When I run the tests I observe that the inner lambda function does not get invoked using the step verifier.
I guess you want to test the class that implements MyLambda interface.
For sure you inject there serviceWebClientInterface as mentioned on code snippet.
To unit test that class, you should mock the serviceWebClientInterface.apiCall() and verify if it was called. As an addition to your actual code snippet.
You can use Mockito library for that purpose.
create a mock:
given(serviceWebClientInterface).willReturn(Mono.just("some text"));
then verify if it is called:
verify(serviceWebClientInterface).apiCall()
I was able to fix this issue by using
StepVerifier.create(response).verifyComplete();
and mocking chain.filter(exchange);

Getting Mockito error: "Wanted but not invoked... actually, there were zero interactions with this mock"

I'm getting the above error whilst running my unit test for a java class in an Android project (in Android Studio).
The class under test:
import android.content.Context;
import android.util.Log;
import **.CustomObject;
import java.util.concurrent.CountDownLatch;
import androidx.annotation.NonNull;
public class CustomClass {
private static final String string = "a";
private static CustomObject customObject = null;
private static CountDownLatch initializedLatch = new CountDownLatch(1);
#NonNull
public static CustomObject1 getCustomObject1() {
try {
initializedLatch.await();
assert customObject != null;
return customObject;
} catch (InterruptedException e) {
throw new RuntimeException(".");
}
}
public static void methodA(final Context context,
final String string1,
) throws exception {
initializedLatch.countDown();
}
public static void methodB(#NonNull final CustomObject customObjectInput) {
customObject = customObjectInput;
}
}
The test class:
import android.content.Context;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import java.util.concurrent.CountDownLatch;
import **.CustomObject;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.verify;
#RunWith(MockitoJUnitRunner.class)
public class CustomClassTest{
#Mock
static CustomObject customObject;
#Mock
static Context context;
#Mock
CountDownLatch mCountDownLatch;
#Mock
CountDownLatch mInitializedLatch;
#InjectMocks
CustomClass customClass;
#Before
public void setUp() {
customObject = Mockito.spy(CustomObject.class);
context = Mockito.spy(Context.class);
}
#Test
public void customClassTest() {
doNothing().when(mInitializedLatch).countDown();
CustomClass.methodB(customObject);
try {
CustomClass.methodA(context, "");
} catch (Exception e) {
e.printStackTrace();
}
verify(mInitializedLatch).countDown();
try {
doNothing().when(mInitializedLatch).await();
} catch (InterruptedException e) {
e.printStackTrace();
}
Class.getCustomObject();
}
The specific message I'm getting when running customClassTest:
Wanted but not invoked:
mInitializedLatch.countDown();
-> at CustomClassTest.methodA(CustomClassTest.java:79)
Actually, there were zero interactions with this mock.
Wanted but not invoked:
mInitializedLatch.countDown();
-> at CustomClassTest.methodA(CustomClassTest.java:79)
Actually, there were zero interactions with this mock.
Running the debugger with break points at each of the relevant lines seems to suggest that the test runs fine (with all the variables being assigned correctly at the right points) until verify(mInitializedLatch).countDown();, when the message appears (and the code stops running).
Any help appreciated, thanks.
UPDATE #1:
Altered the code to remove static keyword:
import android.content.Context;
import android.util.Log;
import **.CustomObject;
import java.util.concurrent.CountDownLatch;
import androidx.annotation.NonNull;
public class CustomClass {
private final String string = "a";
private CustomObject customObject = null;
private CountDownLatch initializedLatch = new CountDownLatch(1);
#NonNull
public CustomObject1 getCustomObject1() {
try {
initializedLatch.await();
assert customObject != null;
return customObject;
} catch (InterruptedException e) {
throw new RuntimeException(".");
}
}
public void methodA(final Context context,
final String string1,
) throws exception {
initializedLatch.countDown();
}
public void methodB(#NonNull final CustomObject customObjectInput) {
customObject = customObjectInput;
}
}
import android.content.Context;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import java.util.concurrent.CountDownLatch;
import **.CustomObject;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.verify;
#RunWith(MockitoJUnitRunner.class)
public class CustomClassTest{
#Mock
CustomObject customObject;
#Mock
Context context;
#Mock
CountDownLatch mCountDownLatch;
#Mock
CountDownLatch mInitializedLatch;
#InjectMocks
CustomClass customClass;
#Before
public void setUp() {
customObject = Mockito.spy(CustomObject.class);
context = Mockito.spy(Context.class);
}
#Test
public void customClassTest() {
doNothing().when(mInitializedLatch).countDown();
customClass.methodB(customObject);
try {
customClass.methodA(context, "");
} catch (Exception e) {
e.printStackTrace();
}
verify(mInitializedLatch).countDown();
try {
doNothing().when(mInitializedLatch).await();
} catch (InterruptedException e) {
e.printStackTrace();
}
customClass.getCustomObject();
}
Error messages now read:
error: non-static method methodA(Context,String) cannot be referenced from a static context
error: non-static method getCustomObject1() cannot be referenced from a static context
The second error message is displayed six times. It seems the code isn't compiling.
In CustomClass the CountDownLatch is declared as static field and it's initialized. If you debug your class you can see Mockito is not mocking/proxing this field. All the code interaction to initializedLatch object are not intercepted by Mockito proxy, so when you set-up your test by doNothing().when(mInitializedLatch).countDown(), actually you're not setting the field into customClass.So when you use verify(mInitializedLatch).countDown(), you're actually saying to Mockito that you expect one interaction with this mock, but no interactions are made due the reason above.
You are getting no invocations because the actual call is not made with your mocked mInitializedLatch object.
While mocking any object, you need to tell the compiler to use this mocked object instead of the one indeed present in your source implementation.
This can be achieved by making the object you are looking to test as an instance variable and passing the mocked object in the constructor.
Then the calls will be made from your mocked object and mockito will be able to track those.
Example:
// Source Code
public class CustomerClass {
private final CountDownLatch initializedLatch
public CustomerClass(CountDownLatch initializedLatch) {
this.initializedLatch = initializedLatch;
}
}
Now, use this instance variable in your code instead of the static variable you defined.
In test code, create constructor of CustomerClass by passing the mocked initializedLatch object and then it will work like charm.
If you are looking to initialize the value of initializedLatch there only. You can do the same by keeping a default constructor alongside the constructor I have defined above.
This default constructor can call the parameterized constructor.
public CustomerClass() {
this(new CountDownLatch(1));
}
Edit:
You also need to change your source implementation.
import android.content.Context;
import android.util.Log;
import **.CustomObject;
import java.util.concurrent.CountDownLatch;
import androidx.annotation.NonNull;
public class CustomClass {
private static final String string = "a";
private CustomObject customObject;
private CountDownLatch initializedLatch;
public CustomClass() {
this(new CountDownLatch(1), null);
}
public CustomClass(CountDownLatch initializedLatch, CustomObject customObject) {
this.initializedLatch = initializedLatch;
this.customObject = customObject;
}
#NonNull
public CustomObject1 getCustomObject1() {
try {
initializedLatch.await();
assert customObject != null;
return customObject;
} catch (InterruptedException e) {
throw new RuntimeException(".");
}
}
public void methodA(final Context context final String string1) throws Exception {
initializedLatch.countDown();
}
public void methodB(#NonNull final CustomObject customObjectInput) {
customObject = customObjectInput;
}
}
Now, above source implementation will use initializedLatch and customObject provided in the constructor.
Test code
import android.content.Context;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import java.util.concurrent.CountDownLatch;
import **.CustomObject;
import org.junit.Test;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.verify;
#RunWith(MockitoJUnitRunner.class)
public class CustomClassTest{
#Mock
CustomObject customObject;
#Mock
Context context;
#Mock
CountDownLatch mInitializedLatch;
#InjectMocks
CustomClass customClass;
#Before
public void setUp() {
customClass = new CustomClass(mInitializedLatch, customObject);
}
#Test
public void customClassTest() {
doNothing().when(mInitializedLatch).countDown();
customClass.methodB(customObject);
try {
customClass.methodA(context, "");
} catch (Exception e) {
e.printStackTrace();
}
verify(mInitializedLatch).countDown();
try {
doNothing().when(mInitializedLatch).await();
} catch (InterruptedException e) {
e.printStackTrace();
}
customClass.getCustomObject();
}
Regarding the error you are getting, I don't think that's because of
the call you are making from the tests.

DAO and Spring Autowired

I tried to create an abstract Dao. I use Spring + Hibernate.
Here's my code.
Main class with configuration:
package ru.makaek.growbox.api;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
#ComponentScan(value = "ru.makaek.growbox")
#EnableAutoConfiguration(exclude = HibernateJpaAutoConfiguration.class)
#EnableTransactionManagement
#SpringBootApplication
public class Application {
#Autowired
private Environment env;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public DataSource getDataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getRequiredProperty("datasource.driver"));
dataSource.setUrl(env.getRequiredProperty("datasource.url"));
dataSource.setUsername(env.getRequiredProperty("datasource.username"));
dataSource.setPassword(env.getRequiredProperty("datasource.password"));
return dataSource;
}
#Bean
public LocalSessionFactoryBean getSessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(getDataSource());
sessionFactory.setPackagesToScan(new String[]{"ru.makaek.growbox"});
return sessionFactory;
}
#Bean
public HibernateTransactionManager getTransactionManager(SessionFactory sessionFactory) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory);
return txManager;
}
}
Rest controller
package ru.makaek.growbox.api.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import ru.makaek.growbox.api.model.data.entities.Device;
import ru.makaek.growbox.api.service.IStructureService;
#RestController
public class DeviceController extends AbstractController {
#Autowired
IStructureService structureService;
#RequestMapping(value = "/devices", method = RequestMethod.POST)
public Answer addDevice(#RequestBody Device device) {
structureService.addDevice(device);
return ok("Device has been added");
}
#RequestMapping(value = "/devices", method = RequestMethod.GET)
public Answer getDevices() {
return ok(structureService.getDevices());
}
#RequestMapping(value = "/devices/{deviceId}", method = RequestMethod.GET)
public Answer getDevice(#PathVariable Long deviceId) {
return ok(structureService.getDevice(deviceId));
}
}
Service layer. Interface
package ru.makaek.growbox.api.service;
import ru.makaek.growbox.api.model.data.entities.Device;
import java.util.List;
public interface IStructureService {
void addDevice(Device device);
List<Device> getDevices();
Device getDevice(Long deviceId);
}
Service layer. Implementation
package ru.makaek.growbox.api.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.makaek.growbox.api.model.data.dao.base.IDao;
import ru.makaek.growbox.api.model.data.entities.Device;
import java.util.List;
#Service
#Transactional
public class StructureService implements IStructureService {
IDao<Device> deviceDao;
#Autowired
public void setDao(IDao<Device> dao) {
deviceDao = dao;
dao.setClazz(Device.class);
}
#Override
public void addDevice(Device device) {
deviceDao.create(device);
}
#Override
public List<Device> getDevices() {
return deviceDao.findAll();
}
#Override
public Device getDevice(Long deviceId) {
return deviceDao.findOne(deviceId);
}
}
Entity
package ru.makaek.growbox.api.model.data.entities;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity(name = "devices")
#Data public class Device extends BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
DAO. Interface
package ru.makaek.growbox.api.model.data.dao.base;
import ru.makaek.growbox.api.model.data.entities.BaseEntity;
import java.util.List;
public interface IDao<T extends BaseEntity> {
T findOne(final long id);
void setClazz(Class<T> clazz);
List<T> findAll();
void create(final T entity);
T update(final T entity);
void delete(final T entity);
void deleteById(final long entityId);
}
Abstract DAO
package ru.makaek.growbox.api.model.data.dao.base;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import ru.makaek.growbox.api.model.data.entities.BaseEntity;
import ru.makaek.growbox.api.util.GBException;
import java.util.List;
public abstract class AbstractDao<T extends BaseEntity> implements IDao<T> {
private Class<T> clazz;
#Autowired
private SessionFactory sessionFactory;
public final void setClazz(Class<T> clazz) {
this.clazz = clazz;
}
public T findOne(long id) {
try {
return (T) getCurrentSession().get(clazz, id);
} catch (Exception e) {
throw new GBException.InternalError(e.getMessage());
}
}
public List<T> findAll() {
try {
return getCurrentSession().createQuery("from " + clazz.getName()).list();
} catch (Exception e) {
throw new GBException.InternalError(e.getMessage());
}
}
public void create(T entity) {
try {
getCurrentSession().persist(entity);
} catch (Exception e) {
throw new GBException.InternalError(e.getMessage());
}
}
public T update(T entity) {
try {
return (T) getCurrentSession().merge(entity);
} catch (Exception e) {
throw new GBException.InternalError(e.getMessage());
}
}
public void delete(T entity) {
try {
getCurrentSession().delete(entity);
} catch (Exception e) {
throw new GBException.InternalError(e.getMessage());
}
}
public void deleteById(long entityId) {
try {
T entity = findOne(entityId);
delete(entity);
} catch (Exception e) {
throw new GBException.InternalError(e.getMessage());
}
}
protected final Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
}
DAO. Implementation
package ru.makaek.growbox.api.model.data.dao;
import org.springframework.stereotype.Repository;
import ru.makaek.growbox.api.model.data.dao.base.AbstractDao;
import ru.makaek.growbox.api.model.data.entities.Device;
#Repository
public class DeviceDao extends AbstractDao<Device> {
}
I have one trouble. When I call GET http://host:port/devices API method I have null in the clazz variable in the AbstractDao.findAll() method. When I was debugging the code i found one interesting thing: in the service layer method deviceDao.getClazz() returned needed clazz (not null). But in method AbstractDao.findAll() I have null in clazz variable. Why? Please help.
Sorry for my English and formulation. I'm new in this site, Spring and English
You are overcomplicating things. Because you are using Spring Boot it is possible to just create generic interface that extends CrudRepository and add the methods you need and are not already present in there.
Take a look here https://docs.spring.io/spring-data/data-commons/docs/1.6.1.RELEASE/reference/html/repositories.html

Spring test service class mocking utility class- Junit and Mockito

I want to write test cases for service layer of spring framework using Junit + Mockito.
How to call the actual service layer method using my ServiceTest class, If i mock the ServiceTest class then it's object wont execute the actual service method code because it wont get the object to call it's methods and if I try with the Spy still it was not working, I tried this example
still I not able to execute the test cases.
MyService.java
#Service
public class MyService{
#Autowired
Utility utility;
public String showResult(){
String result = utility.getName();
return result;
}
}
MyServiceTest.java
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader=AnnotationConfigWebContextLoader.class)
#WebAppConfiguration
public class MyServiceTest {
#Autowired
MyService myService;
#Autowired
Utility utility;
#Test
public void testShowResult() throws Exception {
assertEquals("Test",myService.showResult());
}
#Configuration
static class MykServiceTestContextConfiguration {
#Bean
public MyService myService() {
return new MyService();
}
#Bean
public Utility utility() {
return Mockito.mock(Utility.class);
}
}
}
You have to first mock the Utility class and then have to invoke it before calling your #Test using MockitoAnnotations.initMocks(this) as follows:
MyServiceTest.java
import static org.mockito.Mockito.when;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.AnnotationConfigWebContextLoader;
import org.springframework.test.context.web.WebAppConfiguration;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader = AnnotationConfigWebContextLoader.class)
#WebAppConfiguration
public class MyServiceTest {
#InjectMocks
private MyService myService;
#Mock
private Utility utility;
#Before
public void setupMock() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testShowResult() throws Exception {
when(utility.getName()).thenReturn("Test");
Assert.assertEquals("Test", myService.showResult());
}
#Configuration
static class MykServiceTestContextConfiguration {
#Bean
public MyService myService() {
return new MyService();
}
#Bean
public Utility utility() {
return new Utility();
}
}
}
MyService.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class MyService {
#Autowired
private Utility utility;
public String showResult() {
String result = utility.getName();
return result;
}
}
Utility.java
import org.springframework.stereotype.Component;
#Component
public class Utility {
public String getName() {
return "hello";
}
}
Make use of #Spy
When spy is called, then actual method of real object is called.
https://www.tutorialspoint.com/mockito/mockito_spying.htm
please go through the tutorial
This worked for me
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration
#WebAppConfiguration
public class MyServiceTest {
#Spy
MyService myService;
#Test
public void testShowResult() throws Exception {
assertEquals("Test",myService.showResult());
}
#Service
public class MyService{
public String showResult(){
return "Test";
}
}
}
still having issues share the spring version you are using
How about using #MockBean? It suits Spring + JUnit and, probably you need to implement mock behavior.
I guess that Utility.getName() return "Test" in the test case.
The following is the test code I tried.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(loader = AnnotationConfigWebContextLoader.class)
#WebAppConfiguration
public class MyServiceTest {
#Autowired
MyService myService;
#MockBean
Utility utility;
#Test
public void testShowResult() throws Exception {
Mockito.when(utility.getName()).thenReturn("Test");
assertEquals("Test", myService.showResult());
}
#Configuration
static class MykServiceTestContextConfiguration {
#Bean
public MyService myService() {
return new MyService();
}
}
}

Categories

Resources