Предложения по расширению fit.RowFixture и fit.TypeAdapter, чтобы я мог привязывать/вызывать класс, который хранит attrs на карте

TLDR: я хотел бы знать, как расширить fit.TypeAdaptor, чтобы я мог вызывать метод, который ожидает параметры, поскольку реализация TypeAdaptor по умолчанию вызывает связанный (связанный?) метод путем отражения и предполагает, что это метод без параметров...

Более длинная версия. Я использую fit для создания тестовой системы для своей системы (служба, которая возвращает отсортированный список пользовательских объектов). Чтобы проверить систему, я решил использовать fit.RowFixture для утверждения атрибутов элементов списка.

Поскольку RowFixture ожидает, что данные будут либо общедоступным атрибутом, либо общедоступным методом, я подумал об использовании оболочки для своего пользовательского объекта (скажем, InstanceWrapper) — я также попытался реализовать предложение, данное в эта предыдущая тема о форматировании данных в RowFixture.

Проблема в том, что мой пользовательский объект имеет около 41 атрибута, и я хотел бы предоставить тестировщикам возможность выбирать, какие атрибуты они хотят проверить в этом RowFixture. Кроме того, если я динамически не добавляю поля/методы в свой класс InstanceWrapper, как RowFixture будет вызывать любой из моих геттеров, поскольку оба ожидают, что имя атрибута будет передано в качестве параметра (код скопирован ниже)? Я расширил RowFixture для привязки к моему методу, но я не уверен, как расширить TypeAdaptor, чтобы он вызывался с именем attr. Любые предложения?

public class InstanceWrapper {

    private Instance instance;
    private Map<String, Object> attrs;
    public int index;

    public InstanceWrapper() {
        super();
    }

    public InstanceWrapper(Instance instance) {
        this.instance = instance;
        init(); // initialise map
    }

    private void init() {
        attrs = new HashMap<String, Object>();
        String attrName;
        for (AttrDef attrDef : instance.getModelDef().getAttrDefs()) {
            attrName = attrDef.getAttrName();
            attrs.put(attrName, instance.getChildScalar(attrName));
        }
    }

    public String getAttribute(String attr) {
        return attrs.get(attr).toString();
    }

    public String description(String attribute) {
        return instance.getChildScalar(attribute).toString();
    }
}

public class MyDisplayRules extends fit.RowFixture {

    @Override
    public Object[] query() {
        List<Instance> list = PHEFixture.hierarchyList;
        return convertInstances(list);
    }

    private Object[] convertInstances(List<Instance> instances) {
        Object[] objects = new Object[instances.size()];
        InstanceWrapper wrapper;
        int index = 0;
        for (Instance instance : instances) {
            wrapper = new InstanceWrapper(instance);
            wrapper.index = index;
            objects[index++] = wrapper;
        }
        return objects;
    }

    @Override
    public Class getTargetClass() {
        return InstanceWrapper.class;
    }

    @Override
    public Object parse(String s, Class type) throws Exception {
        return super.parse(s, type);
    }

    @Override
    protected void bind(Parse heads) {

        columnBindings = new TypeAdapter[heads.size()];
        for (int i = 0; heads != null; i++, heads = heads.more) {
            String name = heads.text();
            String suffix = "()";
            try {
                if (name.equals("")) {
                    columnBindings[i] = null;
                } else if (name.endsWith(suffix)) {
                    columnBindings[i] = bindMethod("description", name.substring(0, name.length()
                            - suffix.length()));
                } else {
                    columnBindings[i] = bindField(name);
                }
            } catch (Exception e) {
                exception(heads, e);
            }
        }
    }

    protected TypeAdapter bindMethod(String name, String attribute) throws Exception {
        Class partypes[] = new Class[1];
        partypes[0] = String.class;

        return PHETypeAdaptor.on(this, getTargetClass().getMethod("getAttribute", partypes), attribute);
    }
}

person shuchita    schedule 26.05.2011    source источник


Ответы (1)


Что бы это ни стоило, вот как я в конечном итоге решил проблему:

Я создал пользовательский TypeAdapter (расширяющий TypeAdapter) с дополнительным общедоступным атрибутом (String) attrName. Также:

@Override
public Object invoke() throws IllegalAccessException, InvocationTargetException {

    if ("getAttribute".equals(method.getName())) {
        Object params[] = { attrName };
        return method.invoke(target, params);
    } else {
        return super.invoke();
    }
}

Затем я расширил fit.RowFixture и сделал следующие переопределения:

  • public getTargetClass() - чтобы вернуть ссылку на мой класс
  • protected TypeAdapter bindField(String name) выдает исключение - это защищенный метод в ColumnFixture, который я модифицировал так, чтобы он использовал метод получения моего класса:

    @Override
    protected TypeAdapter bindField(String name) throws Exception {
    
        String fieldName = camel(name);
    
        // for all attributes, use method getAttribute(String)
        Class methodParams[] = new Class[1];
        methodParams[0] = String.class;
    
        TypeAdapter a = TypeAdapter.on(this, getTargetClass().getMethod("getAttribute", methodParams));
    
        PHETypeAdapter pheAdapter = new PHETypeAdapter(fieldName);
        pheAdapter.target = a.target;
        pheAdapter.fixture = a.fixture;
        pheAdapter.field = a.field;
        pheAdapter.method = a.method;
        pheAdapter.type = a.type;
    
        return pheAdapter;
    
    }
    

Я знаю, что это не идеальное решение, но это было лучшее, что я мог придумать. Может быть, я получу некоторые лучшие решения здесь :-)

person shuchita    schedule 15.06.2011