用反射消隐字段

时间:2010-01-20 15:20:08

标签: java unit-testing reflection junit

我正在编写一个Junit测试框架来测试Web服务。

要求输入值来自许多不同的来源,例如早期的Web服务调用或类中的文字。

为实现这一目标,我的构造函数以不同的方式接受不同的输入;到目前为止一切都很简单。

问题是web服务还需要使用完整数据加载和必须的字段有效负载。

而不是在if语句决定是否设置值的情况下乱丢(在某些情况下是冗长的)测试,我写了一个注释@Optional。

添加此注释会使其被以下代码置零:

     /**
     * Find all of the fields annotated with optional and null them
     * @throws IllegalAccessException 
     * @throws IllegalArgumentException 
     */
    private void blankOptionalFields() throws IllegalAccessException{

        for(Field field: this.getClass().getDeclaredFields()){


            Annotation optionalAnnotation = field.getAnnotation(Optional.class);

            if(!(field.isSynthetic()) && optionalAnnotation instanceof Optional){

                field.setAccessible(true);
                try{
                    field.set(this, null);
                }
                catch(IllegalArgumentException e){
                    logger.debug("Tried to set a scalar field to null!", e);
                }
            }
        }
    }

所以有两件事:

1:虽然这有效但感觉很脆弱/危险,但必须有更好的方法吗? 2:如果这不是一种愚蠢的方法,那么设置标量值以适应值的最佳方法是什么?

3 个答案:

答案 0 :(得分:1)

如何定义一个只包含一个空白可选属性的方法的界面呢?您可以测试对象以实现接口并直接调用该方法。

这比使用反射创建捕获所有情况更优雅地处理特定异常:

interface Blankable {

    /** @return true if all optional fields are successfully blanked. **/
    public boolean blankOptionalFields();
}

并使用如:

if (obj implements Blankable) {

    if (!((Blankable) obj).blankOptionalFields()) {

        logger.debug("Could not blank optional fields for " + obj);
    }
}

答案 1 :(得分:0)

我会重构测试,从实际测试代码中分离出初始化代码。就此而言,您可以将实际测试代码(调用Web服务的代码)放入多个测试方法之间共享的方法中。

作为一个半相关的评论:我认为“单元”测试是独立运行服务方法,而“集成”测试则将其作为实际的Web服务来运用。

答案 2 :(得分:0)

我并不喜欢这种方法,因为您将测试代码与生产代码混合在一起。

如果您知道哪些字段是提前强制的,是否可以在设置它们时循环遍历这些字段而不使用复杂的if结构?