当前位置: 首页 > 知识库问答 >
问题:

如何在spock或hamcrest中创建自定义特定于域的断言/匹配器

梁俊友
2023-03-14

我试图在spock或hamcrest中编写一个与域相关的自定义断言/匹配器,但我不确定如何继续。

我曾尝试在hamcrest编写一个自定义匹配器,但到目前为止,这只导致我找到了部分解决方案。

我正在寻找一些指导,关于在这种情况下正确的路线是什么。

域对象:

  • ResultMap有一个对象Map

在我的spock测试中,我想做的事情是:

expect:
  that actualResultMap, matchesInAnyOrder(expectedResultMap)
  or
  that actualResultMap, matches(expectedResultMap) // Will only match if everything is in the same order.

然后,内部代码将评估每个条目,并对内部对象进行适当的测试。

到目前为止,我设法编写了一部分代码来评估一组多重映射,但是我不确定如何将我的测试链接起来。

自定义匹配器:

package com.ps.DE.Test.CustomMatcher

import org.hamcrest.BaseMatcher

class MultimapMatcher {

    /**
     * Checks all the entries in a Multimap with another
     * @param expected
     * @return Shows the failure only if the entries do not match or are not in the same order
     */
    static hasAllInOrder(final com.google.common.collect.Multimap expected){
        [
                matches: { actual ->
                    for(key in actual.keySet()){
                        if (actual.get(key) != expected.get(key)){
                            return false
                        }
                    }
                    return true
                },
                describeTo: { description ->
                    description.appendText("MultiMap entries to be ${expected}")
                },
                describeMismatch: { actual, description ->
                    description.appendText("were ${actual}")
                }
        ]   as BaseMatcher
    }

    /**
     * Checks all the entries in a Multimap with another
     * @param expected
     * @return Shows the failure only if the entries do not match
     */
    static hasAllInAnyOrder(final com.google.common.collect.Multimap expected){
        [
                matches: { actual ->
                    for(key in actual.keySet()){
                        if (!actual.get(key).containsAll(expected.get(key))) {
                            return false
                        }
                    }
                    return true
                },
                describeTo: { description ->
                    description.appendText("MultiMap entries to be ${expected}")
                },
                describeMismatch: { actual, description ->
                    description.appendText("were ${actual}")
                }
        ]   as BaseMatcher
    }
}

测试自定义匹配器:

package com.ps.DE.Test.CustomMatcher

import com.google.common.collect.ArrayListMultimap
import com.google.common.collect.Multimap
import spock.lang.Specification

import static com.ps.DE.Test.CustomMatcher.MultimapMatcher.hasAllInAnyOrder
import static com.ps.DE.Test.CustomMatcher.MultimapMatcher.hasAllInOrder
import static org.hamcrest.Matchers.not
import static spock.util.matcher.HamcrestSupport.that


class MultimapMatcherSpec extends Specification {

    def "Test hasAllInOrder"() {
        def actual = ArrayListMultimap.create();

        // Adding some key/value
        actual.put "Fruits", "Apple"
        actual.put "Fruits", "Banana"
        actual.put "Fruits", "Pear"
        actual.put "Vegetables", "Carrot"

        Multimap<String, String> expected = ArrayListMultimap.create();

        // Adding some key/value
        expected.put("Fruits", "Apple");
        expected.put("Fruits", "Banana");
        expected.put("Fruits", "Pear");
        expected.put("Vegetables", "Carrot");

        expect:

        that actual, hasAllInAnyOrder(expected)
        that actual, hasAllInOrder(expected)
    }

    def "Test hasAllInAnyOrder"() {
        Multimap<String, String> actual = ArrayListMultimap.create();

        // Adding some key/value
        actual.put("Fruits", "Apple");
        actual.put("Fruits", "Banana");
        actual.put("Fruits", "Pear");
        actual.put("Vegetables", "Carrot");

        Multimap<String, String> expected = ArrayListMultimap.create();

        // Adding some key/value
        expected.put("Fruits", "Banana");
        expected.put("Fruits", "Apple");
        expected.put("Fruits", "Pear");
        expected.put("Vegetables", "Carrot");

        expect:
        that actual, hasAllInAnyOrder(expected)
        that actual, not(hasAllInOrder(expected))
    }
}

任何帮助或指导都将不胜感激。

共有1个答案

洪高刚
2023-03-14

你为什么需要定制匹配器?也许,Spock和Groovy足够强大,无需自定义匹配器即可满足您的需求。

要匹配两个Multimap对象以相同顺序具有相同内容,只需执行以下操作:

expected:
actual == expected

在同一个断言中添加更多的代码有什么好处吗?

对于任何顺序的匹配,都有点棘手,但添加排序方法(可以在其他测试类中提取和重用)就足够了。这可能看起来像:

expected:
sortValues(actual) == sortValues(expected)

方法本身:

static Map<String, Collection<String>> sortValues(Multimap<String, String> multimap) {
    multimap.asMap().collectEntries {
        [it.key, it.value.sort(false)]
    }
}

也许为了更好的规范可读性,sortValues()可能具有名称anyOrder(),这将使断言看起来像:

expect:
anyOrder(actual) == anyOrder(expected)

然后,内部代码将评估每个条目,并对内部对象进行适当的测试。

这一部分可以通过equals方法在每个比较对象类型上实现。

 类似资料:
  • 我试图使用JUnit/Hamcrest断言集合至少包含一个自定义逻辑断言为true的元素。我希望有像“anyOf”这样的匹配器,它采用lambda(或匿名类定义),在这里我可以定义自定义逻辑。我试过TypeSafeMatcher,但不知道该怎么处理它。 我不认为任何一个是我想要的,因为这似乎需要一个匹配者的名单。

  • 我正在尝试为Glassfish V3.1.1创建自定义领域,但使用BASIC方法登录时出现了一些LogiException: [#|2012-10-11T22:57:21.625 0200|FINE|glass的鱼3.1.2|org.apache.catalina.authenticator.身份验证库|_ThreadID=35;_ThreadName=线程2; ClassName=org.apa

  • 问题所在 我目前正在尝试使用Hamcrest匹配器来断言返回的列表类型是特定类型。例如,假设我的服务调用返回了以下列表: null 使用Hamcrest匹配器,是否有一种方法可以断言空列表是某种类型的参数化的(例如)?

  • 我对使用hamcrest进行资产评估还很陌生,而且我已经有一个非常糟糕的案例需要测试。 我们有2个不同的自定义对象的数组列表:FilterItem和MyEnum。两者都包含一个属性——比方说“值”——单元测试要传递的属性应该相等。因为对象是不同的,所以我不能简单地断言它们包含的值,这使得断言更加困难。 在每个我想断言的单元测试中,我都将断言逻辑提取到一个新方法中,如下所示: 单元测试现在都通过了,

  • 我正在尝试在log4j2中编写自己的RewritePolicy。文件指出: 然而,我不知道如何将它注入我的配置文件。我如何使它在运行时工作?

  • 问题内容: 我正在尝试在Log4j2中编写自己的RewritePolicy。该文档指出: RewritePolicy是一个接口,允许实现在将LogEvent传递给Appender之前检查并可能对其进行修改。RewritePolicy声明一个必须执行的名为rewrite的方法。该方法通过LogEvent传递,并且可以返回相同事件或创建一个新事件。 这是我的 java类 : 这是我的 yaml配置 文