Hamcrest isEqualIgnoringWhitespace 不忽略空格

Hamcrest isEqualIgnoringWhitespace does not Ignore whitespace

因此,由于我们需要将一些 HTML 解析为 XML 并验证 HTML 中的所有内容都在 XML 文件中,因此我们在 Unittests 中使用 Hamcrest 进行验证.由于我们不能在 XML 文件中获得更多或更少的信息,因此我们有一个不使用 contains 而使用 equalTo 的匹配器很重要。问题是我们解析但必须提取某些元素,因为它们在外部管理的数据模型中是不允许的。我们发现这样做会在某些情况下添加额外的空格(与 Jsoup 有关)。

因此,由于空格与实际内容无关,我们决定暂时忽略它们(因为这纯粹是 PoC),但我们确实希望验证我们的概念。为此,我想出了一个解决方案,它去除了每个空格 (String.replaceAll("\s","")),同时也去除了换行符和制表符。然后将所有文本连接到一个 String 对象中,这使得阅读起来很糟糕,而且在调试时也不是一个很好的做法。所以我选择使用 Hamcrests IsEqualIgnoringWhitespace。测试时我发现它根本没有像名字所暗示的那样做任何事情。在代码中,没有删除空格、制表符或换行符,而是检查当前字符是否为空格,如果是,则之前的字符是否也包含空格。如果是这种情况,它将删除一个空格。所以从根本上讲,它只是将空格标准化为在两个单词之间只包含其中一个。

这里是class中使用的stripSpace方法的代码:

public String stripSpace(String toBeStripped) {
    final StringBuilder result = new StringBuilder();
    boolean lastWasSpace = true;
    for (int i = 0; i < toBeStripped.length(); i++) {
        char c = toBeStripped.charAt(i);
        if (isWhitespace(c)) {
            if (!lastWasSpace) {
                result.append(' ');
            }
            lastWasSpace = true;
        } else {
            result.append(c);
            lastWasSpace = false;
        }
    }
    return result.toString().trim();
}

所以本质上它根本不会忽略空格。那为什么要这样命名呢?

为了给出一些我们想要相互匹配的输入示例,这里是一些有空格但不应该有空格的文本(文本是荷兰语,但这并不重要):

m2 vs. m 2(HTML 原文:m<sup>2</sup>

Tabel 3.1 vs. Tabel 3 .1(HTML 原文:Tabel <a href="link to table">3</a>.1

因此,由于这些文本永远不会被普通的 equalTo 匹配器匹配,equalToIgnoringWhitespaces 实际上应该根据名称匹配它,但它没有。

你们有谁知道是否真的有一个匹配器可以忽略空格?

根据 Javadocs IsEqualIgnoringWhitespace:

Creates a matcher of String that matches when the examined string is equal to the specified expectedString, when whitespace differences are (mostly) ignored.

这在 Matchers Javadocs 中有更详细的解释:

Creates a matcher of String that matches when the examined string is equal to the specified expectedString, when whitespace differences are (mostly) ignored. To be exact, the following whitespace rules are applied:

  • all leading and trailing whitespace of both the expectedString and the examined string are ignored
  • any remaining whitespace, appearing within either string, is collapsed to a single space before comparison

以下测试验证了此行为:

@Test
public void testIsEqualIgnoringWhitespace() {
    // leading and trailing spaces are ignored
    assertThat("m 2", equalToIgnoringWhiteSpace(" m 2 "));

    // all other spaces are collapsed to a single space
    assertThat("m 2", equalToIgnoringWhiteSpace("m     2"));

    // does not match because the single space in the expected string is not collapsed any further
    assertThat("m2", not(equalToIgnoringWhiteSpace("m 2")));
}

所以,这就解释了为什么您会看到您在问题中描述的行为。

回复:

Does anyone of you know if there actually is a matcher that actually ignores whitespaces?

您可以编写自己的匹配器。这是一个例子:

public class IgnoresAllWhitespacesMatcher extends BaseMatcher<String> {
    public String expected;

    public static IgnoresAllWhitespacesMatcher ignoresAllWhitespaces(String expected) {
        return new IgnoresAllWhitespacesMatcher(expected);
    }

    private IgnoresAllWhitespacesMatcher(String expected) {
        this.expected = expected.replaceAll("\s+", "");
    }

    @Override
    public boolean matches(Object actual) {
        return expected.equals(actual);
    }

    @Override
    public void describeTo(Description description) {
        description.appendText(String.format("the given String should match '%s' without whitespaces", expected));
    }
}

使用此匹配器,以下测试通过:

@Test
public void testUsingCustomIgnoringAllWhitespaceMatcher() {
    // leading and trailing spaces are ignored
    assertThat("m2", ignoresAllWhitespaces(" m 2 "));

    // intermediate spaces are ignored
    assertThat("m2", ignoresAllWhitespaces("m     2"));
}