1

I'm attempting to create unit tests for a rest service in my spring servlet. But when the controller object is created by @autowire, then all of its @autowired fields are null.

My test class is as follows, using the SpringJUnit runner and context configuration set

@ContextConfiguration(locations = "ExampleRestControllerTest-context.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class ExampleRestControllerTest {

    @Autowired
    private BaseService mockExampleService;

    @Autowired
    private ExampleRestController testExampleRestController;

The ExampleRestControllerTest-context.xml sets up the service to be mocked and injects the mocked object into the controller

<context:annotation-config/>

<import resource="classpath*:example-servlet.xml"/>

<bean id="mockExampleService" class="org.easymock.EasyMock" factory-method="createMock">
    <constructor-arg index="0" value="za.co.myexample.example.services.BaseService"/>
</bean>
<bean id="testExampleRestController" class="za.co.myexample.example.rest.controller.ExampleRestController">
    <property name="exampleService" ref="mockExampleService"/>
</bean>

The rest of the beans used by the controler are defined in the example-servlet.xml

<bean id="RESTCodeMapper" class="za.co.myexample.example.rest.util.RESTCodeMapper"/>

<bean id="restProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
        <property name="location" value="classpath:RESTServiceCodeMapping.properties"/>
</bean>

Along with my Jax2BMarshaller.

My IDE links to these definitions just fine and if I remove any of the definitions I get an "No qualifying bean" error as expected.

My problem is that when I run my unit tests the controller that is provided has all of its fields as nulls

@Controller
public abstract class BaseRestController {

    private static Logger LOGGER = Logger.getLogger(BaseRestController.class);
    protected final String HEADERS = "Content-Type=application/json,application/xml";
    @Autowired
    protected RESTCodeMapper restCodeMapper;

    @Autowired
    protected BaseService exampleService;

    @Autowired
    protected Jaxb2Marshaller jaxb2Marshaller;

(and its implementing class)

@Controller
@RequestMapping("/example")
public class ExampleRestController extends BaseRestController {

When I run the proper code in my Weblogic server the fields get properly populated. More so if I add these fields in my test class directly those fields also get @autowired correctly. I could thus @autowire those objects in my test class and then set them directly into my controller. But that's not the right way of doing it.

So the question is, why are the autowired fields of an autowired object null in my test class when it autowires those objects directly in the same test class or if I run the code normally on my Weblogic server.

FusionHS
  • 103
  • 1
  • 2
  • 8

1 Answers1

1

In your test class, the @Autowired objects are null because of context configuration, so change it to:

@ContextConfiguration(locations = "ExampleRestControllerTest-context.xml")

to

@ContextConfiguration(locations = "classpath:/ExampleRestControllerTest-context.xml")

in ExampleRestControllerTest

So the question is, why are the autowired fields of an autowired object null in my test class when it autowires those objects directly in the same test class or if I run the code normally on my Weblogic server.

They must be null in autowired objects' constructor. You can try to create @PostConstruct method in autowired object and in this method the autowired objects must be not null

andriy
  • 4,074
  • 9
  • 44
  • 71
  • changing the ContextConfiguration to that still has exactly the same effect. With the ExampleRestController being created via `@Autowire` but its fields created by `@Autowired protected RESTCodeMapper restCodeMapper; @Autowired protected BaseService exampleService; @Autowired protected Jaxb2Marshaller jaxb2Marshaller;` The BaseRestController uses the default constructor with a setter for the service so it can be injected. – FusionHS Jun 25 '15 at 10:14
  • This problem is caused by bean initialization in incorrect order. Beans defined in `ExampleRestControllerTest-context.xml` are initialized before beans in `example-servlet.xml`. Try to add `SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);` inside of `ExampleRestControllerTest` before calling autowired beans – andriy Jun 25 '15 at 12:01
  • I tried, as you suggested, adding `SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);` to `ExampleRestControllerTest`, i also tried `SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(testExampleRestController);` and tried `SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);` within the Controller itself. I've tried removing the import and moving the beans to the context.xml so that the beans are initialized before the controller. All of these things still have exactly the same result; The contoller still have nulls in its fields – FusionHS Jun 25 '15 at 12:45
  • I agree that, that should have worked if the beans were not properly instantiated by spring. But I think using `processInjectionBasedOnCurrentContext()` has the same effect and hits the same problem in that Spring is instantiating the beans as null for some reason. Or at least that's what I think – FusionHS Jun 25 '15 at 12:56
  • yap, it is really strange, because I have very similar scenario. I've found one more difference between yours and mine configurations. I don't believe that it will solve the problem, but you can try. `` tag is missing in your config files. [This](http://stackoverflow.com/a/18178794/548601) answer may explain it better – andriy Jun 25 '15 at 13:25
  • Thanks for your help regardless @andriy. the `` also doesn't do anything. since i map the beans explicitly already in the xml it just causes conflicts – FusionHS Jun 26 '15 at 08:07