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));
Related
I'm new to reactive programming. I want to write some test cases for a reactive mongo repository. I tried to stub some query methods and use step-verifier to check the response, but my test gets fail .
ItemReactiveRepository.java
public interface ItemReactiveRepository extends ReactiveMongoRepository<Item, String> {
Mono<Item> findByDescription(String description);
}
Item.java
#Document
#Data
#AllArgsConstructor
#NoArgsConstructor
public class Item {
#Id
private String id;
private String description;
private Double price;
}
ItemReactiveRepositoryTest.java
#DataMongoTest
#RunWith(SpringRunner.class)
public class ItemReactiveRepositoryTest {
#Autowired
private ItemReactiveRepository itemReactiveRepository;
#Test
public void findById() {
Item itemForTest = new Item("ABC", "Samsung TV", 405.0);
Mockito.when(itemReactiveRepository.findById("ABC")).thenReturn(Mono.just(itemForTest));
StepVerifier.create(itemReactiveRepository.findById("ABC"))
.expectSubscription()
.expectNextMatches(item -> item.getPrice() == 405.0)
.verifyComplete();
}
}
Error I receive when running test
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because:
you stub either of: final/private/equals()/hashCode() methods.
Those methods cannot be stubbed/verified.
Mocking methods declared on non-public parent classes is not supported.
inside when() you don't call method on mock but on some other object.
Are there any limitations to use stubbing when test reactive streams? Or any other standard mechanism to test above scenarios?
Instead of using #Autowired you have to prepare mock for Repository from import org.mockito.Mock;
#Mock
ItemReactiveRepository itemReactiveRepository;
As #Thomas has mentioned, you are not mocking instead using the actual MongoDB using DataMongoTest instead you have to get rid of this and just mock the methods and test your service layer. Autowired is expecting all default configuration and a bean which is prepared by the container for you to use which is not the case, you have to mock and use.
ItemReactiveRepository itemReactiveRepository=org.mockito.Mockito.mock(ItemReactiveRepository.class);
This worked for me.
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.
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.
My REST API generates a password on a POST request and stores it in a DB. For development purpose, I'd like to put it in the response, when a development.mode flag is set to true in the application.properties file.
I would like to test this controller and check that if the flag is true, the password is in the response, if false the password is not.
I would like to know if and how I can dynamically set this property value from each test method.
This is my controller:
#RestController
public class PasswordController {
#Value("${development.mode}")
private boolean isDevelopmentMode;
#RequestMapping(value = "/new", method = RequestMethod.POST)
public ResponseEntity<String> generatePassword(#RequestParam(USERNAME_PARAM) String username) {
String password = manager.generatePassword();
String body = "";
if (isDevelopmentMode) {
body = "New password: " + password;
}
return new ResponseEntity<>(body, HttpStatus.OK);
}
}
I have seen documentation to define different property files for testing, using #PropertySource, but it's at the class level and I would like to avoid creating a different file just to change a flag.
I've also seen posts saying you can use ReflectionUtils.setField to change the value of a private field, but for this I have to explicity instantiate my controller and consequently have some issues with Autowired fields. I've tried this:
#RunWith(SpringRunner.class)
#WebMvcTest(PasswordControllerTest.class)
public class PasswordControllerTest extends OtpTest {
#Autowired
private MockMvc mockMvc;
#Test
public void newRoute_developmentModeIsFalse_responseBodyIsEmpty() throws Exception {
PasswordController controller = new PasswordController();
ReflectionTestUtils.setField(controller, "isDevelopmentMode", false);
MockMvc mvc = MockMvcBuilders.standaloneSetup(new PasswordController()).build();
given(manager.generatePassword(any(String.class))).willReturn("123456");
mvc.perform(post("/new").param(PasswordController.USERNAME_PARAM, "test_user")).andExpect(status().isOk()).andExpect(content().string(""));
}
}
Is there a possibility to set the value of a #Value field in each test method? Should I refactor my code to access it differently?
SOLUTION
Thanks to Borys Zibrov it works with this code:
#RunWith(SpringRunner.class)
#WebMvcTest(PasswordController.class)
public class PasswordControllerTest extends OtpTest {
#Autowired
private MockMvc mockMvc;
#Autowired
private WebApplicationContext applicationContext;
#Test
public void newRoute_developmentModeIsTrue_passwordIsInTheResponseBody() throws Exception {
PasswordController controller = applicationContext.getBean(PasswordController.class);
ReflectionTestUtils.setField(controller, "isDevelopmentMode", true);
given(manager.generatePassword(any(String.class))).willReturn("123456");
mockMvc.perform(post("/new").param(PasswordController.USERNAME_PARAM, "test_user")).andExpect(status().isOk())
.andExpect(content().string("New password: 123456"));
}
}
Getting my controller bean from the application context didn't work at first because in my previous code I was using my test class in WebMvcTest annotation.
You could create another applicationContext-tests.xml, connect it to your test via:
#RunWith(SpringRunner.class)
#WebMvcTest(PasswordControllerTest.class)
#ContextHierarchy({
#ContextConfiguration(locations = "path_to applicationContext-tests.xml")
})
public class PasswordControllerTest extends OtpTest {
and override that property development.mode there.
You could also stick to using ReflectionTestUtils but instead of a direct instantiation use a bean from applicationContext constructed by spring for you, and then set a property on that bean.
Or you could just provide a setter for that field.
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