在测试期间注入具有@Inject的私有字段?

时间:2016-09-21 14:00:27

标签: java java-ee junit cdi

我需要为我的Java类PartitionMapperTest编写一个测试PartitionMapper。此类具有带有@Inject注释的私有字段,但它只有一个无参数构造函数。

对于测试,我想在任何测试之前创建partitionMapper并将值注入其私有字段。然后,测试人员测试映射器的方法mapPartitions并断言值。但是,我不知道如何将这些值注入partitionMapper

PartitionMapper.java

@Named
public class PartitionMapper implements javax.batch.api.partition.PartitionMapper {

    @Inject
    private JobContext jobContext;

    @Inject
    @BatchProperty
    private String fetchSize;

    @Inject
    @BatchProperty
    private String rowsPerPartition;

    // other batch properties ...

    @PersistenceUnit(unitName = "h2")
    private EntityManagerFactory emf;

    @Override
    public PartitionPlan mapPartitions() throws Exception {
        // ...
    }
}

PartitionMapperTest.java

public class PartitionMapperTest {

    private PartitionMapper partitionMapper;

    @Before
    public void setUp() {
        // Prepare JobContext, batch properties to inject ...

        // Instantiation
        partitionMapper = new PartitionMapper();

        // TODO How to inject these objects into partitionMapper?
    }

    @Test
    public void testMapPartitions() throws Exception {
        PartitionPlan partitionPlan = partitionMapper.mapPartitions();
        for (Properties p : partitionPlan.getPartitionProperties()) {
            // Assertions here ...
        }
    }

    // ...
}

我确实实现了基于Mockito和PowerMock的真实PartitionMapperTest,可以在我的GitHub上看到。问题在于有如此多的假设导致用户理解的代码非常差。我正在寻找另一种重构它的解决方案。

2 个答案:

答案 0 :(得分:2)

有没有理由只有一个没有args的构造函数?

我建议您使用构造函数注入而不是字段注入。这可以解决你的问题。

例如,而不是:

public class Foo {
    @Inject
    private Bar bar;
}

这样做:

public class Foo {
    private Bar bar;

    public Foo(@Inject Bar bar) {
        this.bar = bar;
    }
}

如果以这种方式定义注入点,则可以使用干净的API,并且可以在非cdi环境中使用您的类(如单元测试)。

有很多关于“构造函数注入VS字段注入”的资源...也在stackoverflow上,例如https://stackoverflow.com/a/19382081/4864870

答案 1 :(得分:1)

使用受保护的字段而不是私有字段可以在单元测试中模拟字段:

@Named
public class PartitionMapper implements javax.batch.api.partition.PartitionMapper {

    @Inject
    JobContext jobContext;

    @Inject
    @BatchProperty
    String fetchSize;

    @Inject
    @BatchProperty
    String rowsPerPartition;

    // other batch properties ...

    @PersistenceUnit(unitName = "h2")
    EntityManagerFactory emf;

    @Override
    public PartitionPlan mapPartitions() throws Exception {
        // ...
    }
}