Hamcrest isEqualIgnoringWhitespace 不忽略空格

Nat*_*len 2 java whitespace unit-testing hamcrest matcher

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

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

下面是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();
}
Run Code Online (Sandbox Code Playgroud)

所以本质上它根本不会忽略空格。那为什么叫这个名字呢?

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

m2m 2(HTML原:m<sup>2</sup>

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

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

你们中有人知道是否真的有一个实际上忽略空格的匹配器吗?

gly*_*ing 5

根据 Javadocs IsEqualIgnoringWhitespace

创建一个字符串匹配器,当检查的字符串等于指定的 expectedString 时匹配,当空白差异(大部分)被忽略时。

这在MatchersJavadocs中有更详细的解释:

创建一个字符串匹配器,当检查的字符串等于指定的 expectedString 时匹配,当空白差异(大部分)被忽略时。确切地说,应用了以下空白规则:

  • 忽略预期字符串和检查字符串的所有前导和尾随空格
  • 任何剩余的空白,即字符串中出现,已折叠到一个单一的空间比较之前

以下测试验证此行为:

@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")));
}
Run Code Online (Sandbox Code Playgroud)

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

回复这个:

你们中有人知道是否真的有一个实际上忽略空格的匹配器吗?

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

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));
    }
}
Run Code Online (Sandbox Code Playgroud)

使用这个匹配器可以通过以下测试:

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

    // intermediate spaces are ignored
    assertThat("m2", ignoresAllWhitespaces("m     2"));
}
Run Code Online (Sandbox Code Playgroud)