Unit Testing Service Layer in Spring Boot - unit-testing

I have a service layer (Code Below:)
#Service
public class EquityFeedsService {
#Autowired
private EquityFeedsRedisRepositoryImpl equityFeedsRedisRepositoryImpl;
public void save(EquityFeeds equityFeeds) {
logger.info("Inside the save method of EquityFeedsService.");
equityFeedsRedisRepositoryImpl.save(equityFeeds);
}
// other methods
}
Now I am trying to write a Unit Test case for the above method below:
#ExtendWith(SpringExtension.class)
#AutoConfigureMockMvc
public class EquityFeedsServiceTest {
private MockMvc mockMvc;
#InjectMocks
private EquityFeedsService equityFeedsService;
#Mock
private EquityFeedsRedisRepositoryImpl equityFeedsRedisRepositoryImpl;
#BeforeEach
public void setUp() {
mockMvc = MockMvcBuilders.standaloneSetup(equityFeedsService).build();
}
#Test
public void testSaveMethod() {
EquityFeeds equityFeeds = new EquityFeeds(423,"SAPEXTXN1", "GS");
when(equityFeedsRedisRepositoryImpl.save(any(EquityFeeds.class))).thenReturn(new EquityFeeds());
}
}
This code gives me the below Exception:
in line (any(EquityFeeds.class))
Required type:
EquityFeeds (This is my model class)
Provided:
Matcher <com.investmentbank.equityfeedsprocessingupdated.model.EquityFeeds> (This is the fully qualified path name of the mode class)
no instance(s) of type variable(s) T exist so that Matcher<T> conforms to EquityFeeds
and Exception :
Cannot resolve method 'thenReturn(com.investmentbank.equityfeedsprocessingupdated.model.EquityFeeds)'
What is wrong with my Unit Test Case? How do i solve this?

Related

Why is #Inject object(Optional) coming null while running unit test?

I have a class Room, where I inject Optional Person object, this is coming null while running testSuccess. My understanding is it should come non null, since I am setting this to new Person() at the start of the test. Why is it coming null?
public class Room{
#Inject
private Optional<Person> person1
//this is coming null when running test
}
My unit test
public class RoomTest {
#Inject Mocks
private Room testRoom
.....
//Other mocks
private Optional<Person> testPerson
//Not able to mock this since its optional, hence directly setting value in unit test.
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void testSuccess() {
testPerson = Optional.of(new Person());
....
}
}
As the name implies, #InjectMocks only injects #Mocks. The testPerson is not a mock. Why not just add an #Inject-ing constructor to the Room class that would accept a person? This way you could just instantiate a testRoom in your test method and your dependency injection will still work.
public class Room{
private Optional<Person> person;
#Inject
public Room(Optional<Person> person) {
this.person = person;
}
}
public class RoomTest {
#Test
public void testSuccess() {
Optional<Person> testPerson = Optional.of(new Person());
Room room = new Room(testPerson);
...
}
}
That said, if you absolutely want to use the annotations and adding the constructor is not an option for you then you can use PowerMock runner to mock the Optional. Conceptually, it can look like the code below. But usually, if you have to use PowerMock there might be something wrong with the code :)
public class Room{
#Inject
private Optional<Person> person;
}
// This is for JUnit4. Using Powermock with JUnit5 will be more involved
#RunWith(PowerMockitoRunner.class)
#PrepareForTest(Optional.class) // to mock the final class
public class RoomTest {
#InjectMocks
private Room testRoom;
#Mock
private Optional<Person> testPerson;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public void testSuccess() {
...
}
}

Unable to unit test a spring service calling mocked custom repository

I defined a custom repository Interface which get stream of entities through Query.getResultStream
public interface MyRepository<T> {
Stream<T> findByCriteria(...);
}
public class MyRepositoryImpl<T> implements MyRepository<T> {
#Autowired SessionFactory sessionFactory;
public Stream<T> findByCriteria(...) {
...
}
}
and my Repository & Service
#Repository
public interface EntityRepository extends MyRepository<Entity> {
...
}
#Service
#Transactional(readOnly = true)
public class EntityService {
#Autowired EntityRepository entityRepository;
public Stream<Entity> getEntitiesByCriteria(String criteria) {
...
return entityRepository.findByCriteria(...);
}
}
Problem is my Service Unit Test does not see the repository implementation, and always return null without going inside findByCriteria implementation.
ExtendWith(MockitoExtension.class)
class EntityServiceTest {
#InjectMocks EntityService service;
#Mock EntityRepository repository;
#Test
void test() {
...
when(repository.findByCriteria(...))
.thenReturn(...);
service.getEntitiesByCriteria(...); //This does not see the implementation of findByCriteria in MyRepositoryImpl
]
}
I tried many annotations like #RepositoryDefinition in my interface or #EnableJpaRepositories in my test class but nothing seems to work

Junit java.lang.IllegalArgumentException: Could not resolve placeholder 'cors.origin.value' in value "${cors.origin.value}"

It is actually resolved but I will leave here solution if anyone will face the same issue. You have to configure placeholder manually like:
public EventControllerTest() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(eventController)
.addPlaceholderValue("cors.origin.value", "http://localhost:4200")
.build();
}
I am trying to perform simple unit test of some method from controller but I am facing an issue:
java.lang.IllegalArgumentException: Could not resolve placeholder 'cors.origin.value' in value "${cors.origin.value}"
Why is that happen? it is only simple unit test so I do not have to setup whole context for this right?
My code:
request I am calling is API_V1_EVENTS_FIND_BY_GENRE:
public class TestApiUrlStrings {
public static final String API_V1_EVENTS = "api/v1/events";
public static final String API_V1_EVENTS_FIND_BY_GENRE = API_V1_EVENTS + "/Dance?page=0";
}
Unit Test
public class EventControllerTest {
#Mock
EventService eventService;
#InjectMocks
EventController eventController;
MockMvc mockMvc;
public EventControllerTest() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(eventController)
.build();
}
#Test
public void findByGenre() throws Exception {
EventsDTO expected = EventsDTOdatasource.getEventsDTO();
when(eventService.findByGenre(anyString(),anyInt())).thenReturn(expected);
mockMvc.perform(get(TestApiUrlStrings.API_V1_EVENTS_FIND_BY_GENRE)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.events", hasSize(3)));
}
}
And controller
#Slf4j
#CrossOrigin(value = "${cors.origin.value}")
#RestController
#RequestMapping(EventController.API_V1_EVENTS)
public class EventController {
public static final String API_V1_EVENTS = "api/v1/events";
private final EventService eventService;
public EventController(EventService eventService) {
this.eventService = eventService;
}
#GetMapping("/{musicGenre}")
#ResponseStatus(HttpStatus.OK)
public EventsDTO findByGenre(#PathVariable String musicGenre,
#RequestParam(value = "page", defaultValue = "0") Integer pageNum) {
return eventService.findByGenre(musicGenre, pageNum);
}
#PutMapping
#ResponseStatus(HttpStatus.CREATED)
public EventsDTO saveAll(#RequestBody EventsDTO eventsDTO) {
return this.eventService.saveAll(eventsDTO);
}
}
Why exception is pointing to CORS value where I do not even need it here?
How to resolve this? There is not much about such exception anywhere.

Mockmvc Controller throws NullPointerException

maybe someone can tell me why I always get NullPointerException when testing my Controller.
It tells me that the NullPointerException happens here:
mvc.perform(get("/passwordaenderung"))
Here is my code:
public class LagerstandortControllerTest {
#InjectMocks
private PasswordChange passwordChange;
// add #Mock annotated members for all dependencies used by the controller here
private MockMvc mvc;
// add your tests here using mvc.perform()
#Test
public void getHealthStatus() throws Exception {
mvc.perform(get("/passwordaenderung"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.status", is("OK")));
}
#Before
public void createControllerWithMocks() {
MockitoAnnotations.initMocks(this);
MockMvcBuilders.standaloneSetup(new PasswordChange()).build();
}
}
What I want to achieve is to test my controller without loading the whole ApplicationContext.
I had to adapt it in order to avoid a NullPointerException:
Introduced a new class:
public class StandaloneMvcTestViewResolver extends InternalResourceViewResolver {
public StandaloneMvcTestViewResolver() {
super();
}
#Override
protected AbstractUrlBasedView buildView(final String viewName) throws Exception {
final InternalResourceView view = (InternalResourceView) super.buildView(viewName);
// prevent checking for circular view paths
view.setPreventDispatchLoop(false);
return view;
}
}
And in my setup method:
#Before
public void setUp() {
final MainController controller = new MainController();
mvc = MockMvcBuilders.standaloneSetup(controller)
.setViewResolvers(new StandaloneMvcTestViewResolver())
.build();
}
The only problem is now that I get a 404 error.
Do I have to put my index.html in
/src/test/resources
too?

Unit testing callback based on Consumer functional interface

I'm trying to unit test code that runs as callback in a Consumer functional interface.
#Component
class SomeClass {
#Autowired
private SomeInteface toBeMockedDependency;
public method() {
toBeMockedDependency.doSomething(message -> {
// Logic under test goes here
// (implements java.util.function.Consumer interface)
...
});
}
}
#RunWith(MockitoJUnitRunner.class)
public class SomeClassTest {
#InjectMocks
private SomeClass someClass;
#Mock
private SomeInteface toBeMockedDependency;
#Test
public void testMethod() {
...
someClass.method();
...
}
}
Essentially I want to provide the tested code some tested "message" via "toBeMockedDependency".
How can the "toBeMockedDependency" be mocked to provide a predefined message?
Is it the right approach?
Don't try to make toBeMockedDependency automatically call your functional interface. Instead, use a #Captor to capture the anonymous functional interface, and then use your test to manually call it.
#RunWith(MockitoJUnitRunner.class)
public class SomeClassTest {
#InjectMocks
private SomeClass someClass;
#Mock
private SomeInteface toBeMockedDependency;
#Captor
private ArgumentCaptor<Consumer<Message>> messageConsumerCaptor;
#Test
public void testMethod() {
someClass.method();
verify(toBeMockedDependency).doSomething(messageConsumerCaptor.capture());
Consumer<Message> messageConsumer = messageConsumerCaptor.getValue();
// Now you have your message consumer, so you can test it all you want.
messageConsumer.accept(new Message(...));
assertEquals(...);
}
}