如何使用@Parameters在运行之间缓存JUnit类字段

时间:2013-12-18 09:43:33

标签: java junit

让我们假设以下JUnit测试类:

@RunWith(Parameterized.class)
public class MyTestClass {

    private ExpensiveObjectToCreate myObject;

    @Parameters
    public static Collection<Object[]> data() {
        Object[][] data = new Object[][] {
                { "parameter1" },
            { "parameter2" },
                };
        return Arrays.asList(data);
    }

    @Test
    public void test1() {
    }

    @Test
    public void test2() {
    }

    public MyTestClass(String stringParameter) {

        myObject = new ExpensiveObjectToCreate(stringParameter);
    }

}

我有什么方法可以为每个参数集创建一次昂贵的对象吗?我这样说是因为JUnit为每个需要运行的测试创建了一个新的测试类。这意味着昂贵的对象不会被创建2次,但实际上是4次(2个参数集x 2次测试)。当我们有许多测试方法时,这会变得更糟。

另外,将昂贵的对象作为参数发送对我来说不是解决方案,因为我的场景有点复杂(我在JUnit规则中创建了昂贵的对象)。

3 个答案:

答案 0 :(得分:2)

为什么不在测试用例类中推出自定义cacher,它会缓存每个参数创建的实例,并在进一步调用时返回相同的实例。

@RunWith(Parameterized.class)
public class Test {

    private static ExpensiveObjectCacher cacher; //instance which caches parameter instance
    private ExpensiveObject myObject;

    public Test(String value) {
        this.myObject = cacher.get(value); 
    }

    @BeforeClass
    public static void setUpBeforeClass(){
        cacher = new ExpensiveObjectCacher();
    }

    @Parameters
    public static Collection<Object[]> data() {
        Object[][] data = new Object[][] {
                { "parameter1" },
            { "parameter2" },
                };
        return Arrays.asList(data);
    }

    @org.junit.Test
    public void test1(){

    }

    @org.junit.Test
    public void test2(){

    }
}

//caching for test cases. 
class ExpensiveObjectCacher{
    private Map<String, ExpensiveObject> map = new ConcurrentHashMap<String, ExpensiveObject>();

    ExpensiveObject get(String value){
        ExpensiveObject instance = map.get(value);

        if(instance == null){
            instance = new ExpensiveObject(value);
            map.put(value, instance);
        }

        return instance;
    }
}

class ExpensiveObject{
    public ExpensiveObject(String value) {
        System.out.println("Instance created: " + value);
    }
}

输出:

Instance created: parameter1
Instance created: parameter2

答案 1 :(得分:2)

您可以使用参数(此处为简单字符串)中的静态MapExpensiveObjectToCreate的实例。

@RunWith(Parameterized.class)
public fnial class MyTestClass {
    private static final Map<Parameter, ExpensiveObjectToCreate> MAPPING = new HashMap<>();

    private ExpensiveObjectToCreate myEOTC;

    public MyTestClass(String stringParameter) {
        myEOTC = getEOTC(new Parameter(stringParameter));
    }

    private static getEOTC(Parameter parameter) {
        ExpensiveObjectToCreate eotc = MAPPING.get(parameter);
        if (eotc == null) {
            eotc = new ExpensiveObjectToCreate(parameter.stringParameter);
            MAPPING.put(parameter, eotc);
        }
        rturn eotc;
    }

    private static final class Parameter {
        String stringParameter;
        Parameter(String stringParameter) { this.stringParameter = stringParameter; }
        @Override public int hashCode() { ... }
        @Override public boolean equals(Object other) { ... }
    }
 }

但是,如果您还需要限制昂贵对象的数量,则应该做更多的工作,例如缓存可能是一种解决方案。

答案 2 :(得分:1)

如果您使用的是Junit 4:

private static  ExpensiveObjectToCreate myObject;
private static String stringParameter = "some text";

@BeforeClass
public static void setUpBeforeClass() throws Exception {
    myObject = new ExpensiveObjectToCreate(stringParameter);
}

如果是Junit 3:

private static  ExpensiveObjectToCreate myObject;
private static String stringParameter = "some text";

@BeforeClass
protected static void setUpBeforeClass() throws Exception {
    myObject = new ExpensiveObjectToCreate(stringParameter);
}

在这两种情况下,对象都将为所有单元测试创​​建一次。

编辑:字符串我不知道它来自何处,所以我认为所有单元测试的字符串都相同。