比较器的Junit匹配器?

sqserrrh  于 2022-11-11  发布在  其他
关注(0)|答案(5)|浏览(150)

几天来,我一直在使用Junit的Matchers功能,一切都正常,但我正在寻找一个使用比较器进行比较的匹配器,它不依赖于对象等于方法。
我想替换

Assert.assertThat(one, CoreMatchers.equalTo(two)

使用类似于(伪代码)的内容

Assert.assertThat(eins, CoreMatchers.equalTo(operand, new MyComparator())

你知道是否存在一个简单的开箱即用的解决方案吗?我没有在谷歌找到一个,也不想写一个。

ss2ws0br

ss2ws0br1#

现在Hamcrest www.example.com +中支持此功能2.0.0.0。
您可以使用org.hamcrest.comparator.ComparatorMatcherBuilder类别来达成此目的,例如:

ComparatorMatcherBuilder builder = ComparatorMatcherBuilder.comparedBy(equivalenceComparator);
Assert.assertThat(eins, builder.comparesEqualTo(operand));
wlzqhblo

wlzqhblo2#

我在hamcrest 1.3中遇到了同样的问题,通过编写一个匹配器解决了这个问题,这个匹配器遵循IsEqual-Matcher的代码,但是使用了一个给定的比较器而不是Object#equals()。

import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Factory;
import org.hamcrest.Matcher;
import org.junit.Assert;

import java.lang.reflect.Array;
import java.util.Comparator;

/**
 * Is the value equal to another value, as tested by the
 * given Comparator?<br/>
 * Based on the example of {@link org.hamcrest.core.IsEqual}.
 *
 * @author Serhat Cinar
 */
public class IsEqualWithComparator<T> extends BaseMatcher<T> {
    private final Object expectedValue;
    private final Comparator<T> comparator;

    public IsEqualWithComparator(T equalArg, Comparator<T> comparator) {
        expectedValue = equalArg;
        this.comparator = comparator;
    }

    @Override
    public boolean matches(Object actualValue) {
        return areEqual(actualValue, expectedValue, comparator);
    }

    @Override
    public void describeTo(Description description) {
        description.appendValue(expectedValue);
    }

    private static boolean areEqual(Object actual, Object expected, Comparator comparator) {
        if (actual == null) {
            return expected == null;
        }

        if (expected != null && isArray(actual)) {
            return isArray(expected) && areArraysEqual(actual, expected, comparator);
        }

        return comparator.compare(actual, expected) == 0;
    }

    private static boolean areArraysEqual(Object actualArray, Object expectedArray, Comparator comparator) {
        return areArrayLengthsEqual(actualArray, expectedArray) && areArrayElementsEqual(actualArray, expectedArray, comparator);
    }

    private static boolean areArrayLengthsEqual(Object actualArray, Object expectedArray) {
        return Array.getLength(actualArray) == Array.getLength(expectedArray);
    }

    private static boolean areArrayElementsEqual(Object actualArray, Object expectedArray, Comparator comparator) {
        for (int i = 0; i < Array.getLength(actualArray); i++) {
            if (!areEqual(Array.get(actualArray, i), Array.get(expectedArray, i), comparator)) {
                return false;
            }
        }
        return true;
    }

    private static boolean isArray(Object o) {
        return o.getClass().isArray();
    }

    @Factory
    public static <T> Matcher<T> equalTo(T operand, Comparator<T> comparator) {
        return new IsEqualWithComparator<>(operand, comparator);
    }

    public static void main(String argv[]) {
        Assert.assertThat("abc", IsEqualWithComparator.equalTo("ABC", new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.equalsIgnoreCase(o2) ? 0 : -1;
            }
        }));
    }
}
owfi6suc

owfi6suc3#

另一个选择是使用AspectJ框架为对象和可迭代对象定制比较策略。

assertThat(frodo).usingComparator(raceComparator).isEqualTo(sam);
assertThat(fellowshipOfTheRing).usingElementComparator(raceComparator).contains(sauron);

它还具有逐字段比较,例如isEqualToComparingOnlyGivenFields和isEqualToIgnoringGivenFields比较器。

assertThat(frodo).isEqualToComparingOnlyGivenFields(sam, "race.name");
assertThat(frodo).isEqualToIgnoringGivenFields(sam, "name", "age");

因此,在大多数情况下,无需自定义比较策略即可处理Assert

fafcakar

fafcakar4#

我不知道Hamcrest中有什么东西可以做到这一点。您可能需要编写一个自定义匹配器。需要考虑的一件事是:如果equals没有返回true,那么对象是否相等?如果要测试特定的属性,自定义匹配器可能更清楚地表示为FeatureMatcherIs there a simple way to match a field using Hamcrest?)。例如,如果测试的是预期标签:

assertThat(eins, equalToUnderComparison("1", new LabelComparator());

可能更清楚:

assertThat(eins, hasLabel(eq("1")));

编写自定义匹配器并不需要很多代码(编写自定义匹配器),如果它使代码更可读,就没有理由避免它。

vmjh9lq9

vmjh9lq95#

我偶然发现了verify()方法的相同用例。决定实现一个自定义的ArgumentMatcher,它在比较之前简单地复制所有不感兴趣的类属性。

verify(testService).save(eqIgnoreA(saved));

public static Foo eqIgnoreA(Foo expected) {
  return argThat(actual -> {
    actual.setA(expected.getA());
    return expected.equals(actual);
  });
}

相关问题