Mocking a class with Both Constructor and field injection - spring

I have a class, where I added the dependencies as constructor injection as well as one as field injection
#service
public class MyService {
private final ClientOne clientOne;
private final ClientTwo clientTwo;
#Autowired
private SpecialClient specialClient;
public MyService(ClientOne clientOne,
ClientTwo clientTwo){
this.clientOne=clientOne;
this.clientTwo=clientTwo;
}
When I write test case, If I use #InjectMock on MyService , in case of mixed type of dependencies Mockito will use Constructor to create the Mock and my SpecialClient will be null.
SpecialClient an internal dependency so I do not have a setter for it and it is private too.
Workaround
For now I made specialClient package private in above class(removed private before specialClient)
Then explicitly setup the mock in target class after creating the object with constructor code is shown below.
But in reality this should be private, I can still use some ReflectionUtils to set the private field in setup method but that's also another Hack.
Question is
Is there a way Mockito provide a solution for such scenario. to initialize all dependencies ?
class MyServiceTest{
MyService myService;
#Mock
ClientOne clientOne
#Mock
ClientTwo clientTwo
#Mock
SpecialClient specialClient
#BeforeAll
void setup(){
myService = new MyService(clientOne,clientTwo);
myService.specialClient=specialClient;
}
}
And No I can not add specialClient as Constructor Arg, Its actually a requestScope dependency.

You cannot use #InjectMocks to inject the dependencies both by constructor injection and by setter injection, which is clearly documented by #InjectMocks:
Mockito will try to inject mocks only either by constructor injection, setter injection, or property injection in order and as described below. If any of the following strategy fail, then Mockito won't report failure; i.e. you will have to provide dependencies yourself.
Constructor injection; the biggest constructor is chosen, then arguments are resolved with mocks declared in the test only. If the object is successfully created with the constructor, then Mockito won't try the other strategies. Mockito has decided to no corrupt an object if it has a parametered constructor.
Note: If arguments can not be found, then null is passed. If non-mockable types are wanted, then constructor injection won't happen. In these cases, you will have to satisfy dependencies yourself.
You need to turn to Spring-specific tools - let Spring create MyService bean and autowire it into your test:
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {MyService.class})
public class MyServiceTest {
#MockBean
ClientOne clientOne;
#MockBean
ClientTwo clientTwo;
#MockBean
SpecialClient specialClient;
#Autowired
MyService myService;
}

Related

Dependency injection through constructor vs property [duplicate]

So since I've been using Spring, if I were to write a service that had dependencies I would do the following:
#Component
public class SomeService {
#Autowired private SomeOtherService someOtherService;
}
I have now run across code that uses another convention to achieve the same goal
#Component
public class SomeService {
private final SomeOtherService someOtherService;
#Autowired
public SomeService(SomeOtherService someOtherService){
this.someOtherService = someOtherService;
}
}
Both of these methods will work, I understand that. But is there some advantage to using option B? To me, it creates more code in the class and unit test. (Having to write constructor and not being able to use #InjectMocks)
Is there something I'm missing? Is there anything else the autowired constructor does besides add code to the unit tests? Is this a more preferred way to do dependency injection?
Yes, option B (which is called constructor injection) is actually recommended over field injection, and has several advantages:
the dependencies are clearly identified. There is no way to forget one when testing, or instantiating the object in any other circumstance (like creating the bean instance explicitly in a config class)
the dependencies can be final, which helps with robustness and thread-safety
you don't need reflection to set the dependencies. InjectMocks is still usable, but not necessary. You can just create mocks by yourself and inject them by simply calling the constructor
See this blog post for a more detailed article, by one of the Spring contributors, Olivier Gierke.
I will explain you in simple words:
In Option(A), you are allowing anyone (in different class outside/inside the Spring container) to create an instance using default constructor (like new SomeService()), which is NOT good as you need SomeOtherService object (as a dependency) for your SomeService.
Is there anything else the autowired constructor does besides add code
to the unit tests? Is this a more preferred way to do dependency
injection?
Option(B) is preferred approach as it does NOT allow to create SomeService object without actually resolving the SomeOtherService dependency.
Please note, that since Spring 4.3 you don't even need an #Autowired on your constructor, so you can write your code in Java style rather than tying to Spring's annotations.
Your snippet would look like that:
#Component
public class SomeService {
private final SomeOtherService someOtherService;
public SomeService(SomeOtherService someOtherService){
this.someOtherService = someOtherService;
}
}
Good to know
If there is only one constructor call, there is no need to include an #Autowired annotation. Then you can use something like this:
#RestController
public class NiceController {
private final DataRepository repository;
public NiceController(ChapterRepository repository) {
this.repository = repository;
}
}
... example of Spring Data Repository injection.
Actually, In my experience, The second option is better. Without the need for #Autowired. In fact, it is wiser to create code that is not too tightly coupled with the framework (as good as Spring is). You want code that tries as much as possible to adopt a deferred decision-making approach. That is as much pojo as possible, so much such that the framework can be swapped out easily.
So I would advise you create a separate Config file and define your bean there, like this:
In SomeService.java file:
public class SomeService {
private final SomeOtherService someOtherService;
public SomeService(SomeOtherService someOtherService){
this.someOtherService = someOtherService;
}
}
In ServiceConfig.java file:
#Config
public class ServiceConfig {
#Bean
public SomeService someService(SomeOtherService someOtherService){
return new SomeService(someOtherService);
}
}
In fact, if you want to get deeply technical about it, there are thread safety questions (among other things) that arise with the use of Field Injection (#Autowired), depending on the size of the project obviously. Check this out to learn more on the advantages and disadvantages of Autowiring. Actually, the pivotal guys actually recommend that you use Constructor injection instead of Field Injection
I hope I won't be downgraded for expressing my opinion, but for me option A better reflects the power of Spring dependency injection, while in the option B you are coupling your class with your dependency, in fact you cannot instantiate an object without passing its dependencies from the constructor. Dependency Injection have been invented for avoid that by implementing Inversion of Control,so for me option B doesn't have any sense.
Autowired constructors provides a hook to add custom code before registering it in the spring container. Suppose SomeService class extends another class named SuperSomeService and it has some constructor which takes a name as its argument. In this case, Autowired constructor works fine. Also, if you have some other members to be initialized, you can do it in the constructor before returning the instance to spring container.
public class SuperSomeService {
private String name;
public SuperSomeService(String name) {
this.name = name;
}
}
#Component
public class SomeService extends SuperSomeService {
private final SomeOtherService someOtherService;
private Map<String, String> props = null;
#Autowired
public SomeService(SomeOtherService someOtherService){
SuperSomeService("SomeService")
this.someOtherService = someOtherService;
props = loadMap();
}
}
I prefer construction injection, just because I can mark my dependency as final which is not possible while injecting properties using property injection.
your dependencies should be final i.e not modified by program.
There are few cases when #Autowired is preferable.
One of them is circular dependency. Imagine the following scenario:
#Service
public class EmployeeService {
private final DepartmentService departmentService;
public EmployeeService(DepartmentService departmentService) {
this.departmentService = departmentService;
}
}
and
#Service
public class DepartmentService {
private final EmployeeService employeeService;
public DepartmentService(EmployeeService employeeService) {
this.employeeService = employeeService;
}
}
Then Spring Bean Factory will throw circular dependency exception. This won't happen if you use #Autowired annotation in both beans. And this is understandable: the constructor injection happens at very early stage of Spring Bean initialization, in createBeanInstance method of Bean Factory, while #Autowired-based injection happens way later, on post processing stage and is done by AutowiredAnnotationBeanPostProcessor.
Circular dependency is quite common in complex Spring Context application, and it needs not to be just two beans referring one another, it could a complex chain of several beans.
Another use case, where #Autowired is very helpful, is self-injection.
#Service
public class EmployeeService {
#Autowired
private EmployeeService self;
}
This might be needed to invoke an advised method from within the same bean. Self-injection is also discussed here and here.
There is a way to inject the dependencies through constructor using #RequeiredArgsContructor annotation from Lombok
#RequiredArgsConstructor
#Service
class A {
private final B b // needs to be declared final to be injected
}
In this way you don't need to specify a constructor

Logger field injection and unit tests

I have the following piece of code:
#Component
public class MyBean {
#Inject
private Logger logger;
private Service service;
#Inject
public MyBean(Service service) {
this.service = service;
}
}
I used constructor injection in order to have clear list of dependencies required by MyBean, but I have also decided to use field injection for logger (since most the the classes would require this extra parameter in constructor, which just feels not right).
I want to use Mockito for testing and I have the following options to use:
#InjectMocks
I have read in multiple places to avoid it
I can't configure mock before my class is initialized
Inject logger with Whitebox
use of reflection
Use SpringRunner
is it really necessary to create Spring context just to instantiate one class for unit test?
Is there any cleaner way to accomplish that?

Spring #Autowired annotaion

Spring #Autowired
I have a doubt on Spring #Autowired annotation.Please Help...
In Spring mvc ,when I tried #Autowired in this order
Controller--->Service--->Dao
ie,In Controller I autowired Service Class Object , In Service Class Autowire Dao Object.
This Injection chain works perfectly.
Similliarly In strutrs2+Spring ,I applied #Autowired Annotation in this way
Action--->Service-->Dao
This Injection chain also works fine.
If I call a funtion from outside this chain (eg:Custom Taglib class (from jsp)) to funtion in Service class Then in this Service class the Autowired dao object is null(ie,this call braks the chain).
My questions is
Is this #Autowired works in a Injection chain Only?
Beans that have #Autowired fields only have them set if they are sent through the Spring Bean Postprocessor -- that is, like you said, if you autowire them yourself. That is a big reason that constructor injection is much more preferred than field injection. Instead of doing
#Service
public class MyService {
#Autowired
private MyDao dao;
...
}
you should do
#Service
public class MyService {
private final MyDao dao;
#Autowired
public MyService(MyDao dao) {
this.dao = dao;
}
}
That way, when you're in a situation where you can't rely on a service to be post-processed (as in your case of using the jsp tag library), you can simply instantiate a new instance with a MyDao object and be on your merry way.

How to inject Mocks into Spring Service

Environment :
Spring MVC 4
Junit
Mockito
Code :
Spring Service under test :
#Service("abhishekService")
public class AbhishekServiceImpl implements AbhisheskService {
#Autowired
private DaoOne daoOne;
#Autowired
private DaoTwo daoTwo;
#Autowired
private DaoThree daoThree;
#Autowired
private DaoFour daoThree;
}
Junit Test :
public class AbhishekServiceImplTest {
#Mock
private DaoOne daoOne;
#Mock
private DaoTwo daoTwo;
#Mock
private DaoThree daoThree;
#Mock
private UserDao userDao;
private AbhisheskService abhisheskService;
#Before
public void setUp(){
MockitoAnnotations.initMocks(this);
abhisheskService = new AbhishekServiceImpl();
}
}
Issue :
1)As shown in code snippet one , the class under test uses four dependencies.
2)As shown in code snippet two , in junit test case class , all 4 dependencies are mocked using #Mock
3)My question is : how these four mocked objects should be injected into test class ?
4)My class under test doesn't have constructor/setter injection but field injection using #Autowired.
5)I don't want to use #InjectMocks annotation due to its dangerous behavior
as mentioned here
Can anybody please guide on this ?
You are trying to test a class wrongly designed to test the behavior i.e. the properties are not accessible to be mocked. AbhishekServiceImpl has to provide a way to inject the mocks to the class. If you cannot access the fields then it is a clear case of wrongly designed class. Considering that the AbhishekServiceImpl is a class in a legacy code and you are trying to test the behaviour then you can use reflection to inject the mock objects as below:
DaoOne mockedDaoOne = mock(DaoOne.class);
when(mockedDaoOne.doSomething()).thenReturn("Mocked behaviour");
AbhishekService abhishekService = new AbhishekServiceImpl();
Field privateField = PrivateObject.class.getDeclaredField("daoOne");
privateField.setAccessible(true);
privateField.set(abhishekService, mockedDaoOne);
assertEquals("Mocked behaviour", abhishekService.doSomething());
Its very rare that you test behaviour of a class that you have not written yourself. Though I can imagine a use case where you have to test an external library because its author did not test it.
You can mark the junit test with #RunWith(SpringJUnit4ClassRunner.class) and then use #ContextConfiguration to define a context which instantiates the DAOs and service and wires them together.

Trying to generate error about Spring's #Autowired field injection for JUnit

I am working with Spring 4.0.7, and with JUnit about testing of course.
About DI Spring offers #Autowired to be used in three locations
constructor
setter
field
I always work through the two first, why never the third option?
Because I remember have read long time ago about field injection should not be used, because it has a negative consequence about Testing. It does JUnit fails.
Note: Only for Testing is the problem. To runtime or production all goes well
Objective: For demonstration/academic purposes I want generate this problem.
I have the following:
Repository
public interface PersonRepository extends JpaRepository<Person, String>{
}
A Service
#Service
#Transactional
#Profile("failure")
public class PersonFailTestServiceImpl implements PersonService {
private static final Logger logger = ...
#Autowired
private PersonRepository personRepository;
Other Service (calling or using the service shown above)
#Service
#Transactional
#Profile("failure")
public class PersonFailTestProcessImpl implements PersonProcess {
private static final Logger logger = ...
#Autowired
private PersonService personService;
How you can see the two services are based on Field Injection.
Now the testing:
How the beans are loaded
#Configuration
#ComponentScan( basePackages={"com.manuel.jordan.server.infrastructure"},
basePackageClasses={PersonProcess.class,PersonRepository.class, PersonService.class})
public class CentralConfigurationEntryPoint {
}
#ContextConfiguration(classes=CentralConfigurationEntryPoint.class)
public class CentralTestConfigurationEntryPoint {
}
Now the two testing classes
#Transactional
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles({"development","failure"})
public class PersonServiceImplDevelopmentFailureTest extends CentralTestConfigurationEntryPoint {
#Autowired
private PersonService personService;
#Test
public void savePerson01(){
Person person01 = PersonFactory.createPerson01();
personService.save(person01);
personService.printPerson(personService.findOne("1"));
}
#Transactional
#RunWith(SpringJUnit4ClassRunner.class)
#ActiveProfiles({"development","failure"})
public class PersonProcessImplDevelopmentFailureTest extends CentralTestConfigurationEntryPoint{
#Autowired
private PersonProcess personProcess;
Well all the testing methods pass, all green. I don't know if I am missing something or through Spring 4 the problem has been fixed
If this was your premise or problem
Because I remember have read long time ago about field injection
should not be used, because it has a negative consequence about
Testing. It does JUnit fails.
then you thought wrong. There is nothing inherently wrong with using field injection, definitely nothing that would cause JUnit tests to fail in and of itself. If a bean exists, Spring will be able to inject it whether it's in a constructor, a setter method, or a field.
Since you've activated your failure profile, your PersonFailTestServiceImpl bean will be found.
I think I can help. The example code you've posted here is a good example of a system / integration test, not a UNIT test.
If you were UNIT testing PersonFailTestProcessImpl, you would have to set the personRepository dependency yourself through code. But it is private, so how do you do this? You cannot use a constructor or setter since none is provided. This is what is meant by 'hard to unit test'.
Java 5+ provides a way to set private variables like this via reflection (the so-called privileged accessor). Basically, you obtain the class, get the declared field, call its setAccessible method, then you can set its value directly. There are libraries that will do these steps for you, but the point is that this is a pain compared to X.setSomething();
So there is nothing that 'makes jUnit fails' by using #Autowired on a private field. But building an object model without constructors or setters for establishing dependencies is unnecessarily constraining.

Resources