Mongo Repository findById in Java Spring Boot not working - java

I have the following Mongo repository classs in my Spring-boot application, which is called ExpertRepository.java:
import org.bson.types.ObjectId;
import org.springframework.data.mongodb.repository.MongoRepository;
public interface ExpertRepository extends MongoRepository<Experts, ObjectId>{
Experts findBy_id(ObjectId _id);
}
And I have implemented this Service in my ExpertsServiceImpl.java class:
#Service
#RequiredArgsConstructor
public class ExpertsServiceImpl implements ExpertsService{
private final ExpertRepository repository;
public Experts findExpertById(ObjectId id) {
Experts searchedExpert = repository.findBy_id(id);
return searchedExpert;
} }
And I have implemented also the following test class for my Service :
#SpringBootTest
public class ExpertsServiceTest {
#Autowired
private ExpertRepository repository;
#Autowired
private ExpertsServiceImpl service;
Experts demoExpert = new Experts(ObjectId.get(),"Steve Jobs", "Enterpreneur",
Availability.BUSY, Language.CHINESE);
#Before
public void setUp() throws Exception{
service.deleteAll();
service.createExpert(demoExpert);
}
#After
public void tearDown() throws Exception{
service.deleteAll();
}
#Test
public void testfindExpertById(){
ObjectId id = new ObjectId(demoExpert.get_id());
Experts expert = service.findExpertById(id);
assertEquals(demoExpert.get_id(), expert.get_id());
} }
Despite that the test fails and when debugging I figured out that my searchedExpert object in the findExpertById method of the ExpertsServiceImpl class is Null as shown in the picture below:
Does anyone understand why this happens and how I could correct it? I apppreciate any help you can provide

Related

#MockBean service field is always null in a Test class with #WebMvcTest

I'm trying to improve a unit test for a service I'm developing. I read somewhere that it's ideal to use #WebMvcTest annotation over #SpringBootTest when testing the Web or Controller layer.
However, for some reason, a #MockBean service field I am using in the Test class is always NULL.
java.lang.AssertionError: Expecting actual not to be null
In the test class below, serviceIsLoaded() method is always null when I run that single test.
SectionRESTControllerTest.java
#WebMvcTest
public class SectionRESTControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private SectionServiceImpl sectionServiceImpl;
#Test
public void serviceIsLoaded() {
assertThat(sectionServiceImpl).isNotNull();
}
}
SectionServiceImpl.java
#Service
public class SectionServiceImpl implements SectionService {
private final Logger logger = LoggerFactory.getLogger(SectionServiceImpl.class);
#Autowired
private SectionRepository sectionRepo; //saves to section table
#Autowired
private GradeLevelRepository gradeLevelRepo;
#Override
public Section createSection(Section section) {...}
#Override
public Section updateSection(Section request) throws Exception {...}
#Override
public Section getSectionById(Long id) {
return sectionRepo.findById(id).get();
}
#Override
public List<Section> getAllActiveSections() {
return sectionRepo.findSectionByIsActiveTrue();
}
#Override
public List<Section> getAllInActiveSections() {
return sectionRepo.findSectionByIsActiveFalse();
}
#Override
public List<Section> getSectionsByGradeLevelId(Long id) {
return sectionRepo.findByGradeLevelId(id);
}
#Override
public List<Section> getSectionByGradeLevelCode(String code) {
return sectionRepo.findByGradeLevelCode(code);
}
#Override
public List<Section> getSectionByGradeLevelCategory(String category) {
return sectionRepo.findByGradeLevelCategory(category);
}
}
My understanding is, with #WebMvcTest, it does not load the entire application context with all managed beans which makes the UnitTest run faster. Unlike, #SpringBootTest which loads everything when running the UnitTest.
SectionService.java
public interface SectionService {
Section createSection(Section section);
Section updateSection(Section section) throws Exception;
Section getSectionById(Long id);
List<Section> getAllActiveSections();
List<Section> getAllInActiveSections();
List<Section> getSectionsByGradeLevelId(Long id);
List<Section> getSectionByGradeLevelCode(String code);
List<Section> getSectionByGradeLevelCategory(String category);
}
Main class
#SpringBootApplication
public class AutoformSettingsServiceApplication {
public static void main(String[] args) {
SpringApplication.run(AutoformSettingsServiceApplication.class, args);
}
}
Do you have any thoughts or ideas why the #MockBean sectionServiceImpl is null
Thank you.

How to test controller layer on spring-boot by autowiring service?

I am trying to test the functionality of my controller in my API. I have implemented the following service called ExpertsServiceImpl.java:
#Service
#RequiredArgsConstructor
public class ExpertsServiceImpl implements ExpertsService{
private final ExpertRepository repository;
#Override
public Experts createExpert(Experts expert) {
return repository.save(expert);
}
#Override
public void deleteExpert(ObjectId id) {
Experts deleted = findExpertById(id);
if(deleted == null) {
throw new ExpertNotFoundException(id);
}
repository.delete(deleted);
}
public Experts findExpertById(ObjectId id) {
Optional<Experts> searchedExpert = repository.findById(id);
if(searchedExpert.get() == null) {
throw new ExpertNotFoundException(id);
}
return searchedExpert.get();
}
This is my MongoDB repository:
public interface ExpertRepository extends MongoRepository<Experts, ObjectId>{
}
And this is my controller class:
#RestController
#Validated
class ExpertController {
public final ExpertsService service;
public ExpertController(ExpertsService service) {
this.service = service;
}
#PostMapping(path = "/experts/",
consumes = {MediaType.APPLICATION_JSON_VALUE},
produces = {MediaType.APPLICATION_JSON_VALUE}
)
public Experts newExpert(#Valid #RequestBody Experts newExpert) {
return service.createExpert(newExpert);
}
#DeleteMapping("/experts/{id}")
public void deleteBook(#PathVariable ObjectId id) throws Throwable {
service.deleteExpert(id);
}
I am writting the following test class for my controller:
#ActiveProfiles("test")
#RunWith(SpringRunner.class)
#WebMvcTest(controllers = ExpertController.class)
class ExpertControllerTest {
#Autowired
private MockMvc mockMvc;
#Autowired
private ObjectMapper objectMapper;
#Autowired
private ExpertsService expertsService;
#MockBean
private ExpertRepository repository;
Experts demoExpert = new Experts(ObjectId.get(),"Steve Jobs", "Enterpreneur",
Availability.BUSY, Language.CHINESE);
#Before
public void setUp() throws Exception{
expertsService.deleteAll();
expertsService.createExpert(demoExpert);
}
#After
public void tearDown() throws Exception{
expertsService.deleteAll();
}
#Test
public void deleteExpert() throws Exception {
String expertId = demoExpert.getId();
this.mockMvc.perform(MockMvcRequestBuilders
.delete("/experts/{id}", expertId)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(MockMvcResultMatchers.status().isOk());
}
Which throws this error:
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:123)
at org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener.postProcessFields(MockitoTestExecutionListener.java:95)
at org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener.injectFields(MockitoTestExecutionListener.java:79)
at org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener.prepareTestInstance(MockitoTestExecutionListener.java:54)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:244)
at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:98)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$5(ClassBasedTestDescriptor.java:337)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.executeAndMaskThrowable(ClassBasedTestDescriptor.java:342)
at org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor.lambda$invokeTestInstancePostProcessors$6(ClassBasedTestDescriptor.java:337)
at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1654)
at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:312)
Does anyone understand how I could fix this? I guess it has to do with the fact that I am autowiring the Service and Mocking the repository, but not sure how to fix this. I would like to autowire the Service as mocking it wouldnt make much sense for my tests. Anyone knows how I could go about this? I appreciate any help
WebMvcTest only initialise the Controller layer so all service/repository beans are not created and injected. In your case the problem is
#Autowired
private ExpertsService expertsService;
Replace with
#MockBean
private ExpertsService expertsService;
Now you have mock for your service and you can focus on testing the Controller logic only.
if you don't want to mock the service, you can add #Import(ExpertsServiceImpl.class) on top of your test class or use #SpringBootTest as mentioned (but in this case it will load the whole application, which is not really great, performance-wise)

Testing JPA Entities

I want to know how to write Junit test for Spring Repository classes.
As example :
class-AccountMoveActionDet
Jpa interface-AccountMoveActionDetlJpaRepository
And I want to test this repository class work or not.Spring Jpa support some methods like
List findAll();
deleteAll();
I wrote a class just like below:
#RunWith(SpringJUnit4ClassRunner.class)
public class AccountTypeMovementJpaRepositoryTest extends AbstractJpaTest {
#Autowired
AccountTypeMovementJpaRepository accountTypeMovementJpaRepository;
#Override
public void test() {
executeSqlScript("/fixtures/accountTypeMovementJpa.sql");
assertEquals("accountTypeMovementJpaRepository Test", accountTypeMovementJpaRepository.findAll().size(),
JdbcTestUtils.countRowsInTable(getJdbcTemplate(), "COF5REP"));
}
}
Error creating bean with name
'com.gayan.cmp.jparepositories.test.AccountTypeMovementJpaRepositoryTest':
Please help me to resolve this.
If you use spring-boot 1.4 and above the best place to start, Testing the JPA slice :
#RunWith(SpringRunner.class)
#DataJpaTest
public class UserRepositoryTests {
#Autowired
private TestEntityManager entityManager;
#Autowired
private UserRepository repository;
#Test
public void findByUsernameShouldReturnUser() {
this.entityManager.persist(new User("sboot", "123"));
User user = this.repository.findByUsername("sboot");
assertThat(user.getUsername()).isEqualTo("sboot");
assertThat(user.getVin()).isEqualTo("123");
}
}

How to create a bean of repository class

I'm doing unit test using spring mvc test framework.
The following is my source code:
com.exmple.main
MyController.java
#Controller
public class MyController {
#Autowired
private MyService myService;
#RequestMapping(method = RequestMethod.POST)
#ResponseBody
public Map<Object, Object> myControllerFunction(#RequestBody final Object jsonRequest) {
/* do something */
return response;
}
}
MyRepository.java
#Repository
public interface MyRepository extends JpaRepository<My, String> {
#Query(value="select * from my d where (d.start_date<to_date(:date,'YYYY/DD/MM')) and (d.end_date>to_date(:date,'YYYY/DD/MM'))", nativeQuery=true)
List<My> findByDate(#Param("date") String date);
}
MyService.java
public interface MyService {
List<My> findByDate(String date);
}
MyServiceImpl.java
#Service
public class MyServiceImpl implements MyService {
#Autowired
MyRepository destRepo;
#Override
public List<My> findByDate(String date) {
List<My> listDest = destRepo.findByDate(date);
return listDest;
}
}
com.example.test
MyControllerTest.java
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes={TestConfig.class})
#WebAppConfiguration
public class MyControllerTest {
private MockMvc mockMvc;
#Autowired
MyService myService;
#Autowired
protected WebApplicationContext webApplicationContext;
#Before
public void setup() throws Exception {
// this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
#Test
public void listAllMy() throws Exception {
}
}
TestConfig.java
#Configuration
public class TestConfig {
#Bean
public MyService myService() {
// set properties, etc.
return new MyServiceImpl();
}
}
When I run test, the following error is displayed
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException
I know the exception occurred because MyService didn't find any bean of MyRepository.
But I don't know how to create a bean of repository.
Please teach me how to create a bean of repository class using Java (not xml).
You need to enable the JPA repositories in your config class, specify the package that contains the repositories as below
#Configuration
#EnableJpaRepositories(basePackages = {
"com.example.repository"
})
public class TestConfig {
#Bean
public MyService myService() {
// set properties, etc.
return new DestinationServiceImpl();
}
}
Edit: looks like you haven't defined entityManager, and dataSource. Refer to a tutorial here and also answer to similar question here

Mock object method call using Spring Boot and Mockito

I am trying to write a test for this Java SpringBoot's class:
https://github.com/callistaenterprise/blog-microservices/blob/master/microservices/composite/product-composite-service/src/main/java/se/callista/microservices/composite/product/service/ProductCompositeIntegration.java
Specifically, I am trying to "mock" this method call:
URI uri = util.getServiceUrl("product");
I figured out I should "mock" the ServiceUtils object in order to do this. I tried this using the #Mock and #InjectMocks annotations:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = ProductCompositeServiceApplication.class)
public class ProductCompositeIntegrationTest {
#InjectMocks
#Autowired
private ProductCompositeIntegration productIntegration;
#Autowired
private RestTemplate restTemplate;
#Mock
private ServiceUtils util;
private MockRestServiceServer mockServer;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mockServer = MockRestServiceServer.createServer(restTemplate);
}
#Test
public void myTest() {
Mockito.when(util.getServiceUrl("product")).thenReturn(URI.create("http://localhost:8080/test"));
ResponseEntity<Iterable<Product>> products = productIntegration.getAllProducts();
}
}
But this way it still calls the original ServiceUtils object, and not the "mocked" one. Also tried without the #Autowired annotation at the ProductCompositeIntegration, but this results in a NullPointerException.
What am I doing wrong?
My main class looks like this:
#SpringBootApplication
#EnableCircuitBreaker
#EnableDiscoveryClient
public class ProductCompositeServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ProductCompositeServiceApplication.class, args);
}
}
The ServiceUtils object that I am trying to mock is specified in a class, annotated with Spring's #Component annotation to inject it into the other classes using #Autowired.
After a lot of trial and error I managed to solve this problem.
I dropped the
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = ProductCompositeServiceApplication.class)
annotations aboved the test class.
I marked the class that I was testing with #InjectMocks and the dependencies with #Mock:
public class ProductCompositeIntegrationTest {
#InjectMocks
private ProductCompositeIntegration productIntegration;
#Mock
private ServiceUtils util;
private MockRestServiceServer mockServer;
private RestTemplate restTemplate = new RestTemplate();
#Before
public void init() {
MockitoAnnotations.initMocks(this);
mockServer = MockRestServiceServer.createServer(restTemplate);
productIntegration.setRestTemplate(restTemplate);
}
#Test
public void someTests() {
when(util.getServiceUrl("product")).thenReturn(URI.create("http://localhost:8080/test"));
//Test code...
}
}
I'm not sure if this is the best approach ("the Spring way"), but this worked for me.
This article made it all clear to me: http://rdafbn.blogspot.be/2014/01/testing-spring-components-with-mockito.html
You have to write a FactoryBean like
public class MockitoFactoryBean<T> implements FactoryBean<T> {
private Class<T> classToBeMocked;
public MockitoFactoryBean(Class<T> classToBeMocked) {
this.classToBeMocked = classToBeMocked;
}
#Override
public T getObject() throws Exception {
return Mockito.mock(classToBeMocked);
}
#Override
public Class<?> getObjectType() {
return classToBeMocked;
}
#Override
public boolean isSingleton() {
return true;
}
}
In your test-context.xml you have to add the following lines.
<bean id="serviceUtilMock" class="MockitoFactoryBean">
<constructor-arg value="your.package.ServiceUtil" />
</bean>
If you don't use XML configuration, then you have to add the equivalent to above in your Java configuration.

Categories

Resources