I am trying to create my first integration test, inspiring myself from the jhipster project.
In my setup, i use that kind of code:
CampaignController campaignController = new CampaignController();
ReflectionTestUtils.setField(campaignController, "securityService", securityService);
ReflectionTestUtils.setField(campaignController, "campaignService", campaignService);
ReflectionTestUtils.setField(campaignController, "messageService", messageService);
MockMvc restMvcCampaignController = MockMvcBuilders.standaloneSetup(campaignController).setMessageConverters(TestUtil.getCustomJsonMessageConverter()).build();
RestAssuredMockMvc.mockMvc(restMvcCampaignController);
Services are autowired classes.
I would like to know if "ReflectionTestUtils.setField" is a good practice or if there is anything else better I could use ?
Thank you
It's not a good practice. Instead of making it impossible to set the dependencies (other then by reflection), inject the dependencies via a constructor. For example
#Controller
public class Controller {
private CampaignService campaignService;
#Autowired
public Controller(CampaignService campaignService, MessageService messageService) {
//bind fields
}
}
Now you can instantiate the controller easily from the test.
Related
Is it fine to have a #Service annotated class calling another #Service annotated class? Or it is a bad practice?
Eg.:
#Service
public class MyService {
// ...
#Autowired
private MyOtherService myOtherService;
// ...
}
It is not any restriction calling a service from another one. Unless you make circular dependency between services.
Circular dependency : https://en.wikipedia.org/wiki/Circular_dependency
Circular dependency in spring : https://www.baeldung.com/circular-dependencies-in-spring
Its good practice since utility class are being ignored these days, approach getting motivated by horizontal scaling... Surely services got to interact with other.
No need to worry, its like one service manager needs services of another manager.
just only one should be dependent on other, not both.
#Service
public class MyService {
// ...
#Autowired
private MyOtherService myOtherService = new MyOtherService();
// ...}
Try this. It is worked for me. You can use the methods of a service in many sevice.
I have an spring boot app that has a mongo repository and is using spring data to connect to it. This means there's an "entity" class and then a "repository" class.
However, to actually use the repository I need spring to #Autowire my repo to a variable inside another class (we'll call it X) that might want to use it. But if the X class is itself not a spring bean, it's just a regular pojo created by "new X" somewhere then it can't make use of Autowiring and therefore cant use the repo.
This seems like a show stopper... No one could ever make use of a repo outside of some very specific situations like calling the repo directly from your RestController or whatever without any intervening logic. Yet I am sure people are using this.
So my question is how to structure code so that it can be used? Do I need to do a bunch of processing and then return back up to the controller to interact with the databases? Is there a way to create some kind of other "intermediate helper bean" to mediate the connection? What should that look like?
disclaimer: I am fairly new to spring
Perhaps I can post some excerpts that can clarify your situation.
//nothing spring specific
public class MyPojo {
//properties
}
in a different package:
#Repository
public class MyRepositoryImpl implements MyRepository {
//CRUD implementation or whatever
}
in a different package:
#Service
public class MyServiceImpl implements MyService {
#Autowired //constructor-injection
public MyService(MyRepository myRepository) {
this.myRepository = myRepository;
}
private final MyRepository myRepository;
public void myBusinessLogic() {
MyPojo pojo = new MyPojo(); //not dependent on Spring
myRepository.doSomething();
//place calls to X here as needed
}
}
And finally:
#Controller
public class MyController {
#Autowired
public MyController(MyService myService) {
this.myService = myService;
}
private final MyService myService;
#GetMapping("/myPage")
public String doIt() {
myService.myBusinessLogic();
return "myPage";
}
}
Where MyRepository and MyService are interfaces that would contain the contract for their respective implementations.
Single Responsibility Principle
A major point to note is that your POJO isn't going to "use the repo" as you mention in your question. It represents an entity and shouldn't care about any specific repository. And this seems related to your issue - a POJO shouldn't be making calls to a repository (your "X" class in this case). Seems like the design should be revisited if that is the case.
As you say, you can only autowire fields in objects that themselves are autowired. This is inherent to bean injection. You should annotate X with for instance #Component and inject it where you need it.
My application context XML is simple:
<context:component-scan base-package="com.depressio.spring" />
In that package, I have my configuration:
package com.depressio.spring
#Configuration
#ComponentScan(basePackages = "com.depressio")
public class DepressioConfiguration
{
#Inject private ApplicationContext context;
}
Within com.depressio, there's a repository (DAO):
package com.depressio.dao;
#Repository
public class ParameterDAO
{
public Parameter getParameter(long ID) { ... }
}
... and a service where injection is working just fine (no NPE when parameterDAO is used):
package com.depressio.resource;
#Service
#Path("/depressio/parameters")
public class ParameterResource
{
#Inject private ParameterDAO parameterDAO;
#Path("{id}")
public Response getParameter(long parameterID)
{
return Response.ok(parameterDAO.getParameter(parameterID).legacyFormat()).build();
}
}
However, the legacyFormat() method call there constructs another object. Within that object, I have to inject a different DAO (also annotated with #Repository, though). That injection isn't working.
So, we have the original Parameter object:
package com.depressio.domain;
public class Parameter
{
...
public LegacyParameter legacyFormat()
{
return new LegacyParameter(this);
}
}
... and the LegacyParameter where the injection isn't working:
package com.depressio.domain.legacy;
public class LegacyParameter
{
#Inject private LegacyDAO legacyDAO;
....
public LegacyParameter(Parameter newParameter)
{
// NullPointerException when using the injected legacyDAO.
}
}
I've tried a few things, including:
Using an no-args constructor for LegacyParameter, then calling a populate method so I'm not using the injected DAO until after the object is constructed. This didn't work.
Injecting the LegacyDAO into the ParameterResource and passing it in. This worked, but isn't ideal since I have to pass it around a whole lot (which injection should help avoid, no?). It did prove that LegacyDAO is injectible... just not into LegacyParameter apparently.
Adding a #Service, #Component, or #Named annotation on LegacyParameter. All end up with the NullPointerException on the line I try to reference the injected legacyDAO.
What am I missing?
As Sotirios has pointed out, it can't work since you create a regular Java object and do not give Spring a chance to enhance it.
Either let Spring create objects for which you want to enjoy the Spring 'magic' (like setting #Inject dependencies etc).
Or create your own objects and set the dependencies yourself (yourObject.setDao(dao)).
That said, there are exceptional cases in which you still want to create your objects 'on the fly' by yourself but rely on Spring to inject dependencies to these objects. In this case you should call Spring explicitly:
LegacyParameter p = new LegacyParameter(...);
applicationContext.getAutowireCapableBeanFactory().autowireBean(p);
I don't think you really need it in your case.
(see this link inject bean reference into a Quartz job in Spring? for an example when this is really required).
In addition, I would advice to simplify your configuration.
Why do you use both xml-based and java-based configuration that do actually the same? In your example you could keep only one of them and have the same effect.
I want to test my spring mvc controller.
The controller has a service:
#Autowired
UserService userService
And my user service depends on (autowired) my UserDao and some other services like mongoDb etc.
Now I want the business logic to be tested in my UserService, but ofcourse I want to mock the responses from my UserDao and Mongodb etc.
How do I setup my unit test correctly?
Can I re-use the spring container's xml file that has all my beans etc. or do I create a new one? (I'm assuming I have to get the spring container involved here)
Looking for some guidance on this, any tutorials would be greatly appreciated.
Update
What I find strange is that for my spring controller (that doesn't implement from Controller) I was able to access my private varialbe to manually set my service, i.e:
#Controller
public class UserController {
#Autowired
UserService userService;
}
And in my unit test I could do:
UserController controller = new UserController();
controller.userService = ....
But for my UserService, which has UserDao autowired, I can't access the userDao property:
UserService userService = new UserServiceImpl();
userService.userDao = .... // not available
It makes sense since it is private, but how is it working for my controller?
Spring framework has very interesting features for testing. You can take a look at Spring reference guide. It can provide DI even in your JUnit test class.
#RunWith(SpringJUnit4ClassRunner.class)
// ApplicationContext will be loaded from "/applicationContext.xml" and "/applicationContext-test.xml"
// in the root of the classpath
#ContextConfiguration(locations={"/applicationContext.xml", "/applicationContext-test.xml"})
public class MyTest {
// class body...
}
Briefly, you can use your own applicationContext.xml or even define a new one just for testing. I personally use a different one since I define another dataSource dedicated for testing purposes.
What I find strange is that for my spring controller (that doesn't implement from Controller) I was able to access my private varialbe to manually set my service, i.e:
This is easy: the varible in not private.
It has the default visibility ("package private"). This mean you can access them from all classes of the same package.
So if you have a common structure, then the controller and the controller test case are in the same package. Therefore you can modify the ("package private") controller fields. But the controller test case and the service are not in the same packaged, so you can not access the ("package private") service fields.
Can I re-use the spring container's xml file that has all my beans
etc. or do I create a new one? (I'm assuming I have to get the spring
container involved here)
I would advice against creating new xml file. You would end up duplicating lot of stuff and its going to be hard to maintain. There would be proliferation of config files. You put the config required for tests in a different xml and that should not even be deployed to your production box. So far as using the config for your beans, you can employ the mechanism as suggested by #Trein.
For testing spring contrller in general, you may also find this SO Thread useful.
Hope that helps.
When using Spring and Spring's MVC, where should the dependency injection (DI) take place?
Example, if you have a controller, and many actions in the controller.
Would you be doing:
#RequestMapping("/blah")
public String SomeAction()
{
ApplicationContext ctx = new AnnotationConfigApplicationContext();
MyService myService = ctx.getBean("myService");
// do something here
return "someView";
}
Would this be the best practice approach? Or is their a better way?
The whole idea of Dependency Injection is to not have your classes know or care of how they get the objects they depend on. With injection, these dependencies should just "appear" without any request (hence the Inversion of Control). When using ApplicationContext#getBean(String), you're still asking for the dependency (a la Service Locator) and this is not Inversion of Control (even if this allows you to change the implementation easily).
So, instead, you should make your MyController a Spring managed bean and inject MyService using either setter or constructor based injection.
public class MyController {
private MyService myService;
public MyController(MyService aService) { // constructor based injection
this.myService = aService;
}
public void setMyService(MySerice aService) { // setter based injection
this.myService = aService;
}
#Autowired
public void setMyService(MyService aService) { // autowired by Spring
this.myService = aService;
}
#RequestMapping("/blah")
public String someAction()
{
// do something here
myService.foo();
return "someView";
}
}
And configure Spring to wire things together.
Don't use getbean, that loses the purpose of doing DI. Use #Autowired instead. DI is meant to be used in a layered system like view, service, DAO, so that each layer is not depending on each other.
As a compliment to Pascal's post,
Martin Fowler: Inversion of Control Containers and the Dependency Injection pattern is a must read.
And as cometta stated, that you should use #Autowire annotation to achieve that. In addition to that, Spring supports name based and type based convention injections. I suggest you to read on that.