Autowire class's dependencies in jUnit without manual construction

41 Views Asked by At

My Service class has several autowired objects (Stored Procedures, SPs). Rather than a MockBean when/then, one test actually requires me to autowire the SP dependency objects in full, to see which object is being returned.

I can't really construct the dependencies and wire them myself like suggested in this thread (e.g. via ReflectionTestUtils.setField(service, "myService", new SP());). Unfortunately, for these Stored Proc objects, there's no easy constructor for you. They extend org.springframework.jdbc.object.StoredProcedure where the only possible constructor is with an internal datasource, public MySP(@Autowired DataSource dataSource) { .. }.

@Service
public class MyService {

    @Autowired
    StoredProc1 storedProc1;
    @Autowired
    StoredProc2 storedProc2;
    @Autowired
    StoredProc3 storedProc3;

    // NEED TO UNIT-TEST THIS METHOD
    public StoredProc getStoredProc(Params params) {
        // ...
        // returns one of the 3 autowired objects
    }

    public mainServiceMethod(Params params) {
        // Interface implemented by all autowired StoredProc objects
        StoredProc storedProc = getStoredProc(params);
        // ...
        storedProc.someAction();
    }
}

In this example I need to jUnit getStoredProc which returns one of my normally-autowired objects, and see what's being returned (it's like a factory method). But all these objects are NULL during the course of testing, and I can't construct them myself due to the lack of a user-invokable constructor. So I need the full autowired hierarchy to be available for this test. How do I achieve this?

jUnit:

@SpringBootTest
public class MyServiceTest {
    @Autowired
    MyService myService; // actual service is autowired

    // Tried also autowiring the SP Dependencies, but they are NULL
     
}
1

There are 1 best solutions below

5
gene b. On BEST ANSWER

I found the solution. I can @Autowire the Dependency Objects, which will construct them through the Spring configuration with no problem, and then the Service object can be @InjectMocks on which I will set those fields manually with ReflectionUtils.setField(..).

Code:

@SpringBootTest
public class MyServiceTest {
    
     @InjectMocks
     MyService myService; // this will allow us to set Autowired dependencies via setField()

     @Autowired
     StoredProc1 sp1;  // Autowire to enable auto Spring construction
     @Autowired
     StoredProc2 sp2;  // Autowire to enable auto Spring construction
     @Autowired
     StoredProc3 sp3;  // Autowire to enable auto Spring construction

     @Test
     public StoredProc testGetStoredProc(Params p) {

        // Set fields on InjectMocks-enabled Service object
        ReflectionUtils.setField(myService, "sp1", sp1);
        ReflectionUtils.setField(myService, "sp2", sp2);
        // etc.
        // ...            

     }

}

Voila!