Русский English Тэги View Sergey Zolotaryov's profile on LinkedIn Вход
Удобный Matcher для jMock
Постоянная ссылка 02-01-2008 anydoby java

Задача простой в использовании Matcher для jMock, который позвлял бы проверять, что переданный в качестве параметра объект содержит свойства с нужными значениями.

Решение


package com.anydoby.jmock;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.apache.commons.beanutils.PropertyUtils;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;

public class PropertyValueMatcher<T> extends BaseMatcher<T> {

    private final Class<T> valueClass;
    private final HashMap<String, Matcher<?>> propertyValues;

    public PropertyValueMatcher(Class<T> valueClass) {
        this.valueClass = valueClass;
        propertyValues = new HashMap<String, Matcher<?>>();
    }

    public PropertyValueMatcher(Class<T> valueClass, HashMap<String, Matcher<?>> propertyValues) {
        this.valueClass = valueClass;
        if (propertyValues == null) {
            propertyValues = new HashMap<String, Matcher<?>>();
        }
        this.propertyValues = propertyValues;
    }

    /**
     * Creates a matcher which will check that the value is an instance of the
     * specified class.
     * 
     * @param <T>
     * @param valueClass
     * @return matcher, to which one can add validation criteria using the
     *         {@link #withProperty(String, Matcher)}
     */
    public static <T> PropertyValueMatcher<T> valueOfType(Class<T> valueClass) {
        PropertyValueMatcher<T> matcher = new PropertyValueMatcher<T>(valueClass);
        return matcher;
    }

    /**
     * Creates a matcher which will validate target object's property values
     * using the {@link Matchers#equalTo(Object)} matcher and using the sample
     * object as the source for correct values.
     * 
     * @param <T>
     * @param sample
     * @return matcher which will validate target object's properties based on
     *         the sample object properties
     */
    @SuppressWarnings("unchecked")
    public static <T> Matcher<T> propertiesEqualTo(T sample) {
        PropertyValueMatcher<T> matcher = new PropertyValueMatcher<T>((Class<T>) sample.getClass());
        try {
            Map<String, Object> describe = PropertyUtils.describe(sample);
            Set<Entry<String, Object>> entrySet = describe.entrySet();
            for (Entry<String, Object> entry : entrySet) {
                Matcher<Object> equalTo = Matchers.equalTo(entry.getValue());
                matcher.withProperty(entry.getKey(), equalTo);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return matcher;
    }

    /**
     * Adds a property/value pair to validate against the target object.
     * @param property
     * @param value
     * @return this
     */
    public PropertyValueMatcher<T> withProperty(String property, Matcher<?> value) {
        propertyValues.put(property, value);
        return this;
    }

    @Override
    public boolean matches(Object obj) {
        boolean valid = obj.getClass().isAssignableFrom(valueClass);
        if (valid) {
            Set<Entry<String, Matcher<?>>> entrySet = propertyValues.entrySet();
            for (Entry<String, Matcher<?>> entry : entrySet) {
                String key = entry.getKey();
                try {
                    Object propertyValue = PropertyUtils.getProperty(obj, key);
                    if (!entry.getValue().matches(propertyValue)) {
                        valid = false;
                        break;
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }

        return valid;
    }

    @Override
    public void describeTo(Description desc) {
        desc.appendText("object of type " + valueClass + " with the following field values: " + propertyValues);
    }

}

Использование


        mockery.checking(new Expectations() {
            {
                one(smsPushDAO).insert(
                        with(valueOfType(SmsPush.class).withProperty("user", equal(sms.getUser()))
                                .withProperty("text", equal(sms.getText()))));
            }
        });

можно также использовать объект пример для сравнения:


        SmsPush newSmsPush = new SmsPush();
        // initialize sample object

        ...............

        mockery.checking(new Expectations() {
            {
                one(smsPushDAO).insert(with(propertiesEqualTo(newSmsPush)));
            }
        });

Добавить комментарий

Предыдущая статья Маппинг DispatcherServlet на короткий урл Следующая статья Echo2 + Spring + AspectJ