'SpringBeanAutowiringSupport does not inject beans in jUnit tests

I use SpringBeanAutowiringSupport for bean injection in some objects. Problem is, that injection of beans does not work in jUnit tests. For testing is used SpringJUnit4ClassRunner.

public class DossierReportItemXlsImporterImpl implements DossierRerportItemXlsImporer {

    private final Logger logger = Logger.getLogger(getClass());
    // are not autowired.
    @Autowired
    private DossierReportService dossierReportService;
    @Autowired
    private DossierReportItemService dossierReportItemService;
    @Autowired
    private NandoCodeService nandoCodeService;

    public DossierReportItemXlsImporterImpl(){
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
    }

    //...
}


public class DossierRerportItemXlsImporerTest extends AuditorServiceTest{

    // injected OK
    @Autowired
    private DossierReportService dossierReportService;
    @Autowired
    private DossierReportItemService dossierReportItemService;

    @Test
    public void testXlsImport(){
        DossierRerportItemXlsImporer importer = new DossierReportItemXlsImporterImpl();
        importer.processImport(createDossierReport(), loadFile());
        // ...
    }
  // ...
}

Does anyone have any idea, why injection using SpringBeanAutowiringSupport does not work in jUnit tests?



Solution 1:[1]

well spring + junit team have already fixed this . look this link -- >
spring unit testing

otherwise you can call the spring context and use the getBean method , but in that way you can even do it with a simple main test inside your class instead of junit test

**note if you use the spring + junit config you have to put the test-spring-context.xml into the test package

Solution 2:[2]

I made my own version that supports passing in an ApplicationContext not just limited to WebApplicationContext. This will allow it to work in both test and normal context.

/**
 * This is an implementation of {@link org.springframework.web.context.support.SpringBeanAutowiringSupport} that
 * has a fallback that can be used in unit tests.
 */
public final class SpringBeanAutowiringSupport {
    private static final ThreadLocal<ApplicationContext> applicationContextThreadLocal = new ThreadLocal<>();

    private SpringBeanAutowiringSupport() {}

    public static void setApplicationContext(final ApplicationContext applicationContext) {

        applicationContextThreadLocal.set(applicationContext);
    }

    public static void processInjectionBasedOnCurrentContext(Object target) {

        var cc = ContextLoader.getCurrentWebApplicationContext();
        if (cc != null) {
            org.springframework.web.context.support.SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(target);
        } else if (applicationContextThreadLocal.get() != null) {
            AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
            bpp.setBeanFactory(applicationContextThreadLocal.get().getAutowireCapableBeanFactory());
            bpp.processInjection(target);
        }

    }

    public static void unload() {

        applicationContextThreadLocal.remove();

    }
}

To make it easier to use on tests, I add a TestExecutionListener

public class SpringBeanAutowiringSupportTestExecutionListener extends AbstractTestExecutionListener {

    @Override
    public void afterTestMethod(final TestContext testContext) {

        SpringBeanAutowiringSupport.unload();

    }

    @Override
    public void beforeTestMethod(final TestContext testContext) {

        SpringBeanAutowiringSupport.setApplicationContext(testContext.getApplicationContext());
    }
}

Then use it in my tests with

@RunWith(SpringRunner.class)
@TestExecutionListeners(listeners = {SpringBeanAutowiringSupportTestExecutionListener.class}, mergeMode = MERGE_WITH_DEFAULTS)
public class MyTest {
...
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2