#WebMvcTest No qualifying bean of type repository - unit-testing

I'm writing a controller test where controller looks like
#RestController
public class VehicleController {
#Autowired
private VehicleService vehicleService = null;
...
}
While the test class looks like
#RunWith(SpringRunner.class)
#WebMvcTest(VehicleController.class)
public class VehicleControllerTest {
#Autowired
private MockMvc mockMvc = null;
#MockBean
private VehicleService vehicleServie = null;
#Test
public void test() {
...
}
}
When I run this test it fails with the following error
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.database.repositories.SomeOtherRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Here, SomeOtherRepository is not used in a given controller or service.
If I do #MockBean for SomeOtherRepository the test works but the same problem occurs for the rest of the repositories.
#MockBean private SomeOtherRepository someOtherRepository = null
...
# Bunch of other repositories
Ideally I should not be concerned about all the repositories except the one's I'm using. What am I missing here? How can I avoid writing bunch of #MockBeans?

You have specified
#WebMvcTest(VehicleController.class)
which is fine, however you might find some beans from other dependencies, such as a custom UserDetailsService, some custom validation, or #ControllerAdvice that are also being brought in.
You can exclude these beans by using exclude filters.
#WebMvcTest(controllers = VehicleController.class, excludeFilters = #Filter(type = FilterType.ASSIGNABLE_TYPE, classes = CustomUserDetailsService.class)

Your VehicleService depends on SomeOtherRepository, so you have to mock it too in your test class. Try adding:
#MockBean private SomeOtherRepository someOtherRepository
in your VehicleControllerTest class.

Related

Spring boot Unit test with #WebMvcTest - execution doesn't enter service layer from controller and returns null without error

I am writing unit test for a controller of my spring boot application.
I have typical MVC classes: ObjectSchemaController, ObjectSchemaService and ObjectSchemaDao.
I have written unit test with #WebMvcTest and mocked my service and dao class with #MockBean. (following this guide: https://www.baeldung.com/spring-boot-testing)
Below is my unit test :
#RunWith(SpringRunner.class)
#WebMvcTest(ObjectSchemaController.class)
public class ObjectSchemaControllerTest2 {
#Autowired
private MockMvc mvc;
#MockBean
private ObjectSchemaService service;
#MockBean
private ObjectSchemaDao dao;
#Autowired
ObjectMapper objectMapper;
#Test
public void testCreateObjectSchemaPass() throws Exception {
String payload = "{\"some_key\":\"some val\"}";
ObjectSchema objectSchema = objectMapper.readValue(payload, ObjectSchema.class);
Mockito.when(service.createSchema(objectSchema))
.thenReturn(objectSchema);
Mockito.when(dao.createSchema(objectSchema)).thenReturn(objectSchema);
mvc.perform(MockMvcRequestBuilders.post("/objectservice/schema/")
.contentType("application/json")
.content(objectMapper.writeValueAsString(objectSchema)))
.andExpect(status().isOk());
}
}
below is my service class:
#Service
public class ObjectSchemaService {
#Autowired
ObjectSchemaDao objectSchemaDao;
public ObjectSchema createSchema(#Valid ObjectSchema objectSchema)throws Exception {
return objectSchemaDao.createSchema(objectSchema);
}
}
The issue I am facing with Unit test is, the service layer doesn't get executed and returns null value.
When I debug, I can see execution reaching in my controller class and ObjectSchemaService as being mockito-mocked in the controller. But the execution never goes in service layer and the value returned by service method is null.
I have referenced other guides- they are doing similar steps. But its not working for me. What am I missing here?
I have also seen this post with similar issue.
Unit Test POST with #WebMvcTest - #MockBean Service returns null
I made sure the input objects to both my actual controller and the one I am passing in unit case are instances of same class.
You are mocking the ObjectSchemaService but no behaviour is expected.
You need to setup the behaviour for the services that are mocked. So depending on the method signature and result somethink like.
Mockito.when(service.createSchema(Mockito.any(ObjectSchema.class)).thenReturn(objectSchema);
At the moment the ObjectSchemaService mock just returns a default value which is null in your case.
In order to be transparent and unobtrusive all Mockito mocks by default return 'nice' values. For example: zeros, falseys, empty collections or nulls.
If you update your answer with details for ObjectSchemaService I could also update my answer.
You mock ObjectSchemaService so you need to tell the service how mock the values from the service when a method is called. If you don't mock the values of the service Mockito don't know what they have to return always give you null. Not need to mock ObjectSchemaDao in this test.
Note: I use Lombok in the code as ObjectSchema.builder() to return the object with the Id when is stored in the database, you can use a constructor. Assuming the service return the object.
The code looks like this:
import static org.mockito.BDDMockito.given;
#Test
public void testCreateObjectSchemaPass() throws Exception {
String payload = "{\"some_key\":\"some val\"}";
ObjectSchema objectSchema = objectMapper.readValue(payload, ObjectSchema.class);
given(service.createSchema(objectSchema)).willReturn(
ObjectSchema.builder()
.id(1)
.someKey("Some Val")
.build());
mvc.perform(MockMvcRequestBuilders.post("/objectservice/schema/").contentType("application/json").content(objectMapper.writeValueAsString(objectSchema)))
.andExpect(status().isOk());
}

Repository Test in spring boot leads to Unknown entity Exception

com.mohendra.user
server
Application.class //Main class
package2
package3
domain
Campaigns.class
SmsDomainPackage.class
repository
CampaignRepository.class
The above is my folder structure, I am tryring to test CampaignRepository using spring dataJpaTest ,
I have written the following test
#ComponentScan(basePackages = "com.mohendra.user")
#EntityScan(basePackageClasses = SmsDomainPackage.class)
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Application.class)
#DataJpaTest
#RestClientTest
public class CampaignRepositoryTest {
#Autowired
private TestEntityManager entityManager;
#Autowired
private CampaignRepository repository;
#Before
public void setUp() throws Exception {
}
#Test
public void findByCode() {
Campaigns campaigns = new Campaigns();
campaigns.setName("Name");
campaigns.setCode("HELP123");
campaigns.setStartDate(new Date());
campaigns.setEndDate(new Date());
this.entityManager.persist(campaigns);
Campaigns campaigns1 = repository.findByCode("HELP123");
System.out.println();
}
}
The test gives an exception of
java.lang.IllegalArgumentException: Unknown entity:
com.mohendra.user.package3.domain.Campaigns
I have also used #ComponentScan as you can see, and I've also used #EntityScan to try scan entities from packages, but both of them dont work.
I cannot change my folder structure to make it standard, as it is not my project. Is there a solution to it?
The Application class should be in the root package. That way you will not need any #CompontenScan or #EntityScan because Spring Boot scans everything below your root package
Therefor I recomment to put Application.class in the package com.mohendra.user
And you have to decide which test slice you want. You have three:
#SpringBootTest(classes = Application.class)
#DataJpaTest
#RestClientTest
But I assume that you only want #DataJpaTest

Spring Boot controller unit test : Failed to load ApplicationContext

I have a simple spring boot controller and I want to write unit test for it but there is an error. I've googled for hours but still cannot find the solution. Here is code:
HelloController.java
#RestController
public class HelloController {
#Autowired
private HelloService helloService;
#GetMapping("/hello")
public String sayHello(){
return helloService.sayHello();
}
}
HelloService.java:
#Service
public class HelloService {
public String sayHello(){
return "Hello";
}
}
And unit test file:
HelloControllerTest.java:
#RunWith(SpringJUnit4ClassRunner.class)
#WebMvcTest(HelloController.class)
public class HelloControllerTest {
#Autowired
private MockMvc mockMvc;
#Mock
private HelloService helloService;
#Before
public void setUp(){
MockitoAnnotations.initMocks(this);
}
#Test
public void sayHello() throws Exception {
when(helloService.sayHello()).thenReturn("thach");
mockMvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string("thach"));
}
}
But there is an error:
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:99)
at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:122)
at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:105)
at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:74)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:312)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:284)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.lang.IllegalArgumentException: Cannot load an ApplicationContext with a NULL 'contextLoader'. Consider annotating your test class with #ContextConfiguration or #ContextHierarchy.
at org.springframework.util.Assert.notNull(Assert.java:134)
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContextInternal(CacheAwareContextLoaderDelegate.java:57)
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:91)
... 24 more
Can any one help me ? I am just a newbie to Spring boot
I had similar issue. Please see code below:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
public class ApplicationControllerTest {
#Autowired
MockMvc mockMvc;
#MockBean
ApplicationService applicationService;
#Test
public void testGetImagePath() throws Exception {
RequestBuilder requestBuilder = MockMvcRequestBuilders.get("/application/get-image")
.contentType(MediaType.IMAGE_GIF);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
System.out.println(result.getResponse());
}
Please see below test case execution:
Check Annotations you used i.e. :
1) #RunWith(SpringRunner.class)
2) #SpringBootTest
3) #AutoConfigureMockMvc
For anyone that runs into the same issue - It is important to use #MockBean. (#Mock won't cut it)
See https://spring.io/guides/gs/testing-web/:
We use #MockBean to create and inject a mock for the GreetingService (if you do not do so, the application context cannot start), and we set its expectations using Mockito.
So it is likely all may have been fine if OP just replaced
#Mock
private HelloService helloService;
with
#MockBean
private HelloService helloService;
So the additional class annotations from the accepted answer should not be necessary
if converted into #SpringBootTest it will becomes integration testing. but we want to test only specific controller (unit testing) with #WebMvcTest so how it will become a feasible solution.
I had the same problem and tried different ways, but none of them didn't work, Finally, I included two annotations to my Test Class which resolved my problem:
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#AutoConfigureMockMvc
HelloControllerTest {
}
If you don't want to generate random port to test your API just add the following annotations:
#SpringBootTest
#AutoConfigureMockMvc
HelloControllerTest {
}
What's missing in here is the #SpringBootTest annotation. This annotation is used to load #Configuration classes for testing and start the embedded container with the default port.
If a #Configuration class is not specified, it would use the default #SpringBootApplication class, since it has #Configuration inside its annotation.

Mocking field in #Mock class

Since I am new to Mockito, I would like to know, how can I mock a method inside a class, which actually is also annotated with #Mock.
Example:
#RunWith(MockitoJUnitRunner.class)
public class someServiceTest {
#InjectMocks
private MainService mainService;
#Mock
private HelpService helpService;
#Mock
private SecondHelpService secondHelpService;
Now there is this helpService class, which contains a method, which is used to test MainService.
#Service
#Transactional(propagation = Propagation.SUPPORTS)
public class HelpService {
// I want this method to be mocked
private boolean checkSomething(String name, date) {
return ProcessService.checkIfJobHasRun(name, date);
}
I tried to use #InjectMocks on HelpService as well, by adding ProcessService #Mock in someServiceTest, but Mockito doesn't allow that. And as a result, it throws me NullPointerException. How do I fix that?
#InjectMocks should only be used on the class under test. It does not make sense to inject dependencies into mocks as they do not have any implementation.
If you can make the method public you could mock it as follows:
doReturn(true).when(helpService)
.checkSomething(Mockito.any(String.class), Mockito.any(Date.class));

Mocking EntityManager (Mockito)

I have the following code in one of my classes:
#PersistenceContext
protected EntityManager entityManager;
public entryPoint() {
for(Animal:getTheAnimals()) {
System.out.println(Animal.getName());
}
}
private List<Animal> getTheAnimals() {
return List<Animal>entityManager.createNamedQuery("myQuery").setParameter("myParam", new Date()).getResultList();
}
In my test class I have the following:
#Mock
private EntityManager entityManager;
#Mock
private Query query;
#Autowired
private ClassToTest classToTest;
#Test
public void someTest() {
List<Animal> list = new ArrayList<Animal>();
Mockito.when(entityManager.createNamdeQuery("myQuery")).thenReturn(query);
Mockito.when(query.setParameter(any(String.class), any(java.util.Date.class)).getResultList()).thenReturn(list);
...something more here...
}
As you can see the expected behavior is that the empty list is returned, and zero animal names get printed. However that is not the case and the actual animals from the db are being returned in the list. What am I missing? I tried several variations of this with the same result.
Thanks for reading.
In your question, you use #Autowired directly on the field for the system under test, which seems to instruct Spring to resolve the dependencies. It likely does so from your actual (production) configuration.
By comparison, a common Mockito annotation is #InjectMocks, which ignores Spring, instantiates the object using as many #Mock objects as possible.
Related SO question: Injecting into #Autowired variable during testing