3

I have an application that uses SpringBoot for dependency injection and the app works fine, but testing fails because @Autowired fields aren't being injected during tests.

@SpringBootApplication public class ProcessorInterface { protected final static Logger logger = Logger.getLogger( ProcessorInterface.class ); public static void main(String[] args) { try { SpringApplication.run(ProcessorInterfaceRunner.class, args); } catch (Exception ex) { logger.error("Error running ProcessorInterface", ex); } } } @Component @Configuration @ComponentScan public class ProcessorInterfaceRunner implements CommandLineRunner { protected final static Logger logger = Logger.getLogger( ProcessorInterface.class ); @Autowired private RequestService requestService = null; @Autowired private ValidatorService validatorService = null; @Override public void run(String... args) throws Exception { ESPOutTransaction outTransaction = null; outTransaction = new ESPOutTransaction(); // initialize outTransaction fields ... // done initializing outTransaction fields if (validatorService.isValid(outTransaction)) { System.out.println(requestService.getRequest(outTransaction)); } else { System.out.println("Bad Data"); } } } @Service public class ESPRequestService implements RequestService<ESPOutTransaction> { @Autowired ValidatorService validatorService = null; @Override public String getRequest(ESPOutTransaction outTransaction) throws IllegalArgumentException { if (!validatorService.isValid(outTransaction)) { throw new IllegalArgumentException("Invalid parameters in transaction object. " + outTransaction.toString()); } StringBuffer buff = new StringBuffer("create request XML"); buff.append("more XML"); return buff.toString(); } } @Service public class ESPValidatorService implements ValidatorService { private static org.apache.log4j.Logger logger = Logger.getLogger(ESPValidatorService.class); // declare some constants for rules private static final int MAX_LENGTH_XYZ = 3; @Override public boolean isValid(OutTransaction outTransaction) { ESPOutTransaction espOutTransaction = (ESPOutTransaction)outTransaction; boolean isValid = true; if (espOutTransaction == null) { logger.warn("espOutTransaction is NULL"); isValid = false; } else { // XYZ is required if (espOutTransaction.getXYZ() == null) { logger.warn("XYZis NULL\r\n" + espOutTransaction.toString()); isValid = false; } // XYZ max length = MAX_LENGTH_XYZ if (espOutTransaction.getXYZ() != null && espOutTransaction.getPubCode().trim().length() > MAX_LENGTH_XYZ) { logger.warn("XYZis too long (max length " + MAX_LENGTH_XYZ + ")\r\n" + espOutTransaction.toString()); isValid = false; } } return isValid; } } 

These all work and I get good output when I run the app. When I try to test it though, it fails because it can't find ESPValidatorService to inject into ESPRequestService

@RunWith(Suite.class) @SuiteClasses({ ESPOutTransactionValidatorTest.class, ESPRequestTest.class }) public class AllTests {} @RunWith(SpringRunner.class) @SpringBootTest(classes = {ESPRequestService.class}) public class ESPRequestTest { @Test public void testGetRequest() { ESPRequestService requestService = new ESPRequestService(); String XYZ = "XYZ"; ESPOutTransaction outTransaction = null; outTransaction = new ESPOutTransaction(); outTransaction.setXYZ(XYZ); String strRequest = "some expected request XML"; String request = requestService.getRequest(outTransaction); assertEquals(request, strRequest); } } @RunWith(SpringRunner.class) @SpringBootTest(classes = ESPValidatorService.class) public class ESPOutTransactionValidatorTest { @Test public void testIsValid() { ESPValidatorService validatorService = new ESPValidatorService(); ESPOutTransaction outTransaction = null; // test request = null assertFalse(validatorService.isValid(outTransaction)); String XYZ = "XYZ"; outTransaction = new ESPOutTransaction(); outTransaction.setXYZ(XYZ); // test all good assertTrue(validatorService.isValid(outTransaction)); // test XYZ outTransaction.setXYZ(null); assertFalse(validatorService.isValid(outTransaction)); outTransaction.setXYZ("ABCD"); // too long assertFalse(validatorService.isValid(outTransaction)); outTransaction.setXYZ(XYZ); } } 

How can I get the unit tests to auto wire?

1 Answer 1

4

I see two problems :

1) you don't rely on Spring beans but you create instances with the new operator.

Instead of writing :

ESPRequestService requestService = new ESPRequestService(); 

you should let Spring inject the instance :

@Bean ESPRequestService requestService; 

2) The @SpringBootTest configuration is not correct.

In each test, you specified a very specific bean class in the classes attribute of @SpringBootTest :

@SpringBootTest(classes = ESPValidatorService.class) public class ESPOutTransactionValidatorTest { 

and

@SpringBootTest(classes = {ESPRequestService.class}) public class ESPRequestTest { 

But classes attributes of @SpringBootTest serves to specify the annotated classes to use for loading an ApplicationContext.

The annotated classes to use for loading an ApplicationContext. Can also be specified using @ContextConfiguration(classes=...). If no explicit classes are defined the test will look for nested @Configuration classes, before falling back to a SpringBootConfiguration search.

So all configuration classes and beans of your application may not be discovered and loaded in the Spring container .

To be able to load all application beans during your tests, the most simple way is not specifying the classes attribute in the @SpringBootTest annotation :

@SpringBootTest public class ESPRequestTest { ...} 

It will look for a Spring bean that holds the @SpringBootConfiguration.
Ideally, it will found the @SpringBootApplication bean of your application.
If the package of the test class is located inside the package (or at a lower level) of the @SpringBootApplication class, it should be automatically discovered.

Otherwise the other way is specifying a configuration that will allow to load all required beans :

@SpringBootTest(classes = MySpringBootApplication.class) public class ESPRequestTest { ...} 
Sign up to request clarification or add additional context in comments.

1 Comment

This wasn't the only problem I had, but it got me pointed in the right direction.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.