Hamcrest Bean Matchers – 哈姆克雷斯特Bean匹配者

最后修改: 2018年 3月 23日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Hamcrest is a library that provides methods, called matchers, to help developers write simpler unit tests. There are plenty of matchers, you can get started by reading about some of them here.

Hamcrest是一个提供方法的库,称为匹配器,以帮助开发人员编写更简单的单元测试。有很多匹配器,您可以通过阅读其中一些匹配器来开始。

In this article, we’ll explore beans matchers.

在这篇文章中,我们将探讨Bean匹配器。

2. Setup

2.设置

To get Hamcrest, we just need to add the following Maven dependency to our pom.xml:

要获得Hamcrest,我们只需要在我们的pom.xml中添加以下Maven依赖。

<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>java-hamcrest</artifactId>
    <version>2.0.0.0</version>
    <scope>test</scope>
</dependency>

The latest Hamcrest version can be found on Maven Central.

最新的Hamcrest版本可以在Maven Central找到。

3. Bean Matchers

3.Bean Matchers

Bean matchers are extremely useful to check conditions over POJOs, something that is frequently required when writing most unit tests.

Bean匹配器在检查POJO的条件时极为有用,这在编写大多数单元测试时经常需要。

Before getting started, we’ll create a class that will help us through the examples:

在开始之前,我们将创建一个类,它将帮助我们完成这些例子。

public class City {
    String name;
    String state;

    // standard constructor, getters and setters

}

Now that we’re all set, let’s see beans matchers in action!

现在我们都准备好了,让我们来看看Bean匹配器的运作情况吧!

3.1. hasProperty

3.1.hasProperty

This matcher is basically to check if certain bean contains a specific property identified by the property’s name:

这个匹配器基本上是为了检查某些bean是否包含由属性名称确定的特定属性

@Test
public void givenACity_whenHasProperty_thenCorrect() {
    City city = new City("San Francisco", "CA");
    
    assertThat(city, hasProperty("state"));
}

So, this test will pass because our City bean has a property named state.

因此,这个测试将通过,因为我们的City bean有一个名为state的属性。

Following this idea, we can also test if a bean has certain property and that property has certain value:

按照这个思路,我们也可以测试一个Bean是否有某些属性,并且该属性有某些值。

@Test
public void givenACity_whenHasPropertyWithValueEqualTo_thenCorrect() {
    City city = new City("San Francisco", "CA");
        
    assertThat(city, hasProperty("name", equalTo("San Francisco")));
}

As we can see, hasProperty is overloaded and can be used with a second matcher to check a specific condition over a property.

我们可以看到,hasProperty是重载的,可以与第二个匹配器一起使用,以检查一个属性的特定条件。

So, we can also do this:

因此,我们也可以这样做。

@Test
public void givenACity_whenHasPropertyWithValueEqualToIgnoringCase_thenCorrect() {
    City city = new City("San Francisco", "CA");

    assertThat(city, hasProperty("state", equalToIgnoringCase("ca")));
}

Useful, right? We can take this idea one step further with the matcher that we’ll explore next.

很有用,对吗?我们可以用我们接下来要探讨的匹配器把这个想法再向前推进一步。

3.2. samePropertyValuesAs

3.2.samePropertyValuesAs

Sometimes when we have to do checks over a lot of properties of a bean, it may be simpler to create a new bean with the desired values. Then, we can check for equality between the tested bean and the new one. Of course, Hamcrest provides a matcher for this situation:

有时当我们必须对一个bean的许多属性进行检查时,创建一个具有所需值的新bean可能会更简单。然后,我们可以检查被测试的Bean和新Bean之间是否相等。当然,Hamcrest为这种情况提供了一个匹配器。

@Test
public void givenACity_whenSamePropertyValuesAs_thenCorrect() {
    City city = new City("San Francisco", "CA");
    City city2 = new City("San Francisco", "CA");

    assertThat(city, samePropertyValuesAs(city2));
}

This results in fewer assertions and simpler code. Same way, we can test the negative case:

这将导致更少的断言和更简单的代码。同样,我们可以测试负面情况。

@Test
public void givenACity_whenNotSamePropertyValuesAs_thenCorrect() {
    City city = new City("San Francisco", "CA");
    City city2 = new City("Los Angeles", "CA");

    assertThat(city, not(samePropertyValuesAs(city2)));
}

Next, well see a couple of util methods to inspect class properties.

接下来,我们可以看到几个检查类属性的利用方法。

3.3. getPropertyDescriptor

3.3.getPropertyDescriptor

There’re scenarios when it may come in handy being able to explore a class structure. Hamcrest provides some util methods to do so:

在某些情况下,能够探索一个类的结构可能会很方便。Hamcrest提供了一些利用方法来做到这一点。

@Test
public void givenACity_whenGetPropertyDescriptor_thenCorrect() {
    City city = new City("San Francisco", "CA");
    PropertyDescriptor descriptor = getPropertyDescriptor("state", city);

    assertThat(descriptor
      .getReadMethod()
      .getName(), is(equalTo("getState")));
}

The object descriptor retrieves a lot of information about the property state. In this case, we’ve extracted the getter’s name and assert that it is equal to some expected value. Note that we can also apply other text matchers.

对象描述符检索了很多关于属性状态的信息。在这种情况下,我们已经提取了getter的名字,并断言它等于某个预期值。请注意,我们也可以应用其他文本匹配器。

Moving on, the last method we will explore is a more general case of this same idea.

接下来,我们将探讨的最后一种方法是这一想法的一个更普遍的案例。

3.4. propertyDescriptorsFor

3.4.propertyDescriptorsFor

This method does basically the same as the one in the previous section, but for all the properties of the bean. We also need to specify how high we want to go in the class hierarchy:

这个方法基本上和上一节中的方法一样,只是针对Bean的所有属性。我们还需要指定我们想在类的层次结构中走多高的位置。

@Test
public void givenACity_whenGetPropertyDescriptorsFor_thenCorrect() {
    City city = new City("San Francisco", "CA");
    PropertyDescriptor[] descriptors = propertyDescriptorsFor(
      city, Object.class);
 
    List<String> getters = Arrays.stream(descriptors)
      .map(x -> x.getReadMethod().getName())
      .collect(toList());

    assertThat(getters, containsInAnyOrder("getName", "getState"));
}

So, what we did here is: get all the property descriptors from the bean city and stop at the Object level.

所以,我们在这里所做的是:从Bean city 中获取所有的属性描述符,并在Object层停止。

Then, we just used Java 8’s features to filter the getter methods.

然后,我们就用Java 8的特性来过滤getter方法。

Finally, we used collections matchers to check something over the getters list. You can find more information about collections matchers here.

最后,我们使用集合匹配器在getters列表中检查一些东西。你可以在这里找到更多关于集合匹配器的信息

4. Conclusion

4.结论

Hamcrest matchers consist of a great set of tools to be used across every project. They’re easy to learn and become extremely useful in short time.

Hamcrest匹配器由一套伟大的工具组成,可在每个项目中使用。它们很容易学习,并在短时间内变得非常有用。

Beans matchers in particular, provide an effective way of making assertions over POJOs, something that is frequently required when writing unit tests.

Beans匹配器尤其提供了一种有效的方法来对POJO进行断言,这在编写单元测试时经常需要。

To get the complete implementation of this examples, please refer to the GitHub project.

要获得这个例子的完整实现,请参考 GitHub项目