Mockito Bug in Spring 2.0.0.RELEASE - java

I updated my project with the latest revision of Spring (2.0.0.RELEASE) and while my tests worked in 2.0.0.RC1, now it doesn't work and it keeps giving me this error :
org.mockito.exceptions.base.MockitoException:
Cannot instantiate #InjectMocks field named 'service'! Cause: the type 'PersonService' is an interface.
You haven't provided the instance at field declaration so I tried to construct the instance.
Examples of correct usage of #InjectMocks:
#InjectMocks Service service = new Service();
#InjectMocks Service service;
//and... don't forget about some #Mocks for injection :)
Here I made a minimal project where you can change the version in the pom file to see it succeed on 2.0.0.RC1 and fail in 2.0.0.RELEASE.
For the a full minimal test - please turn to gituhub.

From the documentation for the #InjectMocks
Mockito cannot instantiate inner classes, local classes, abstract classes and of course interfaces.
In your case you should use inside your test:
#InjectMocks
private PersonServiceImpl underTest;
I have checked in your sample from github, if you change to the implementation of service - tests will be passed

Related

Trouble executing a unit test that should ignore Spring annotations on the unit under test

I'm trying to execute a unit test for a service class that has an #Async("asyncExecutor") annotated method. This is a plain JUnit test class with no Spring runners and no intention of using Spring at all in the unit test. I get the exception,
BeanFactory must be set on AnnotationAsyncExecutionAspect to access qualified executor 'asyncExecutor'
Where asyncExectuor is the name of the bean to be used during normal execution. My configuration class looks like this and I solved that previous error message at runtime by adding the mode = AdviceMode.ASPECTJ portion. This service works at runtime without issue in an Async way.
#Configuration
#EnableAsync(mode = AdviceMode.ASPECTJ)
public class AsyncConfiguration {
#Bean(name = "asyncExecutor")
public Executor asyncExecutor() {
...
}
}
I don't understand why the Spring context is being constructed at all in the unit test. The test class is simply annotated #Test on the methods with no class annotations and no mention of Spring. I was hoping to unit test this service class method as a regular method ignoring the async nature, but the annotation is being processed for some reason.
I'm contributing to a much larger gradle + Spring 4 project that I'm not fully knowledgeable about. Is there anything I should be looking for to see if a Spring context is being created by default for all tests?
As you noticed, Spring context is not loaded, that is the reason of your error. Try to initialize Spring context in your test by adding #RunWith and #ContextConfiguration annotations

Mockito injects mocks twice with JUnit 5

I started testing Spring Boot 2.0.0 and I encountered a strange behaviour with Mockito 2.17.0 and JUnit 5.1.0.
From what I saw, the way to get the mocks injected into the desired bean is to use the new #ExtendWith annotation with the MockitoExtension class.
So, here's my test class:
#ExtendWith(MockitoExtension.class)
class MyServiceTest {
#Mock
private A a;
#Mock
private B b;
#InjectMocks
private MyService myService;
// The test methods are omitted
}
That seemed fine but I found that the mocks didn't get called as expected and I figured out that this was due to a different instance of a and b inside the test class and the service itself.
Actually, it's because of the MockitoExtension being applied twice and the second time it is applied, the myService field isn't evaluated to null (obviously) which imply that the newly created mocks (a and b) aren't set to the current myService instance or a new one either.
Am I forgetting something?
I assume I could handle the mocks myself but I think that it isn't the purpose of the InjectMocks annotation.
Thank you for your time.
It looks like you hit Mockito issue: mockito#1346.
It's already fixed, so you may wait for a public release or use dev build 2.17.2: https://bintray.com/mockito/maven/mockito-development/2.17.2 (release notes)

Scalamock testing Java dependency injection

I use Scalamock for unit testing my Java project.
Project contains classes that use Java CDI style DI:
class Resource {
#Inject
private Service service;
.....
}
How can I inject mock as a Service instance?
With Mockito I'm able to use #InjectMocks, but I definitely want to use Scalamock.
Currently ScalaMock does not support Mockito's #InjectMocks equivalent.
In case of setter/constructor injection you can inject your mocks manually. In case of field injection you could access the private fields using reflection, but that would be very cumbersome.
Please create new ScalaMock feature request (https://github.com/paulbutcher/ScalaMock/issues) - if it gets upvoted we can implement it.

Difference between #InjectMocks and #Autowired usage in mockito?

When I was writing test case using the Mockito and Junit, I was using the #InjectMocks for the class to be tested. In other parts of project, I also see #Autowired is being used for the class to be tested.
When can I use #InjectMocks and #Autowired? What is the difference between two when we are trying to use them with class to be tested?
#InjectMocks is a Mockito mechanism for injecting declared fields in the test class into matching fields in the class under test. It doesn't require the class under test to be a Spring component.
#Autowired is Spring's annotation for autowiring a bean into a production, non-test class.
If you wanted to leverage the #Autowired annotations in the class under test, another approach would be to use springockito which allows you to declare mock beans so that they will be autowired into the class under test the same way that Spring would autowire the bean. But typically that's not necessary.
#InjectMocks annotation tells to Mockito to inject all mocks (objects annotated by #Mock annotation) into fields of testing object. Mockito uses Reflection for this.
#Autowired annotation tells to Spring framework to inject bean from its IoC container. Spring also uses reflection for this when it is private field injection.
You can even use even use #Inject annotation (part of Java EE specification) with the same effect.
But I would suggest to look at benefits of Constructor injection over Field injection. In that case you don't need to use #InjectMocks at all, because you can pass mocks into testing object via constructor. There wouldn't be Reflection needed under the hood in your test nor in production.
If you want to create integration test with subset of Spring beans I would suggest to take a look at #DirtiesContext annotation. It is part of Spring framework module commonly called "Spring Test".

Mocking local object created by spring application context using Mockito

I am trying to mock a local object, using Mockito Framework, that is being created from the spring application context; But every time I run the application its fails to replace the original object with the mocked object.
Here is the original class's code spinets:
public void executeMyJob(){
ApplicationContext springContext = ApplicationContextUtil.getApplicationContext();
MusicEAO music= (MusicEAO) springContext.getBean("MusicEAO");
List<Brand> dataList =music.getAll();
......
}
I want to mock the MusicEAO so when the getAll() method is called, it will use the mock object.
Below is my test class code snippets:
#Mock
MusicEAO musicEAO;
when(musicEAO.findAll()).thenReturn(myDefinedList);
How can I resolve this issue?
It's hard to tell from the cod you posted but the problem might be that you are mocking MusicEAO in your test but the code you are executing is using a Spring ApplicationContext to get a reference to the MusicEAO bean.
Your original class should not use MusicEAO music= (MusicEAO) springContext.getBean("MusicEAO"); but instead have the bean injected by Spring using #Autowired through a constructor or a setter method (or other dependency injection method). You test will then be able to easily inject a mock version.
class MyJobClass {
MusicEAO music;
#Autowired
public MyJobClass(MusicEAO musicEao) {
this.music = musicEao;
}
public void executeMyJob(){
List<Brand> dataList =music.getAll();
......
}
}
When you say
every time I run the application it fails to replace the original
object with the mocked object
You shouldn't have to run the application to run a unit test for this class - are you asking how to inject mocks into a running application?
.
It doesn't work this way. In your current code :
The following instance is the one in your test :
#Mock MusicEAO musicEAO;
But in your production code, you are using Spring to acquire the Music instance :
MusicEAO music= (MusicEAO) springContext.getBean("MusicEAO");
Nowhere you seem to say to spring that you want the Music mock to be affected to MusicEAO bean name.
If you are doing a Unit Test I would recommand you to avoid messing with Spring, if that's an integration test, then you'll have to find a way to create the mock and pass it over to spring.
For example you can create the mock in the Spring context, autowire it in your test.
Also, I wouldn't recommand the use of static calls in this situation to acquire the Spring context in order to finaly get a hold on the Music object. it makes me think of Spring as a registry which isn't really the case. Spring is a container. Instead you should try to refactor your code in such a way that the Music bean is wired (#Autowired, setters, etc.) in ExecutionJob.
Then it would be even easier to write a Unit Test with JUnit and Mockito, with annotations like #Mock and #InjectMocks.
Hope that helps.

Categories

Resources