Spring dependency injection null when running a te

2019-07-18 09:26发布

I'm working with Spring 3.0 and jUnit 4.8 and I'm trying to develop some unit test .

In fact, I'm only trying to set a property (a file) of a bean using dependency injection in a test case definined in the XML loaded in the application context used by the jUnit.

I'm using an XML file configuration loaded using the annotation for jUnit 4 aproach. This is the main BaseTest that all test classes used:

@ContextConfiguration("/test-context.xml")
@RunWith(SpringJUnit4ClassRunner.class)
@Ignore
public class BaseTest { ... }

And this is a section of the test-context.xml

<context:component-scan base-package="com.test" />  

<bean id="ExtractorTest" class="com.test.service.ExtractorTest">
    <property name="file" value="classpath:xls/SimpleFile.xls"></property>
</bean>

So what I'm trying to do in my class with the test (ExtractorTest) is only set the 'file' property with a file loaded within the classpath, nothing else.

Here is a section of the class with the test:

public class ExtractorTest extends BaseTest {

    private Resource file;
    private InputStream is;

    public void setFile(Resource file) {
        this.file = file;
    }

    @Before
    public void init() {
        this.is = this.getClass().getResourceAsStream("/xls/SimpleFile.xls");
        Assert.assertNotNull(is);
    }

    @Test
    public void testLoadExcel() throws IOException {
        // file is always null, but the InputStream (is) isn't!
        Assert.assertNotNull(file.getFile());
        InputStream is = new FileInputStream(file.getFile());
        HSSFWorkbook wb = new HSSFWorkbook(new POIFSFileSystem(is));
        // todo...
    }

}

The problem is that the setter works, because I've added a breakpoint and Spring is setting it's property ok. But when the test method starts it's null, may be because it's another instance that is running, but why? How I can set the 'file' to be loaded using the XML of the application context for testing? I'm not able to assign it using jUnit and I don't understand why and how to do it. I'm trying to avoiding writing in the @Before method, but I don't know it's a good approach definitely...

Thank you.

PD: Sorry about my english ;-)

1条回答
叼着烟拽天下
2楼-- · 2019-07-18 10:14

Your configuration doesn't work because Spring doesn't create the instance of ExtractorTest which JUnit uses; instead the instance is created by JUnit and then passed to Spring for post processing.

The effect you see is because the application context creates a bean with the id ExtractorTest but nobody ever uses that.

Pseudocode:

ApplicationContect appContext = new ...
appContext.defineBean("ExtractorTest", new ExtractorTest()); // Calls setter

ExtractorTest test = new ExtractorTest(); // Doesn't call setter
test.postProcess(appContext); // inject beans from appContext -> does nothing in your case

So the solution is to define a bean file:

<bean id="file" class="..." />

(see the documentation how to build a Resource bean) and then let Spring inject that:

@Autowired
private Resource file;
查看更多
登录 后发表回答