Skip to content

orien/bean-matchers

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Bean Matchers

Maven Central License Build Status Codecov

Beans are prevalent in our Java world, however these simple structures are commonly untested. Over the course of a project they can be inflicted with copy and paste errors, hashCode, equals and toString methods fall out of sync as new properties are added.

Enter Bean Matchers. The Bean Matchers project provides a series of Hamcrest matchers for testing Java beans. This provides an easy way to gain confidence that your beans are correct without needing to consume time writing explicit tests for each property. Ensure a no-args constructor exist. Getters and setters are correctly defined for each property. Properties are compared in equals, influence the generated hashCode, and are present in the output of the toString method.

Special attention has been given to the readability of these matchers. It is important that our tests describe the intent of the code being tested.

Bean Matchers is released under the 3-Clause BSD License.

Quick Start

  1. Add the Bean Matchers dependency to your Maven project (Check the Central Repository for the latest version):

    <dependency>
       <groupId>com.google.code.bean-matchers</groupId>
       <artifactId>bean-matchers</artifactId>
       <version>0.14</version>
       <scope>test</scope>
    </dependency>
  2. Test your bean:

    import static com.google.code.beanmatchers.BeanMatchers.*;
    import static org.hamcrest.CoreMatchers.allOf;
    import static org.hamcrest.MatcherAssert.assertThat;
    
    public class MyBeanTest {
    
        // One big test
        @Test
        public void testBean() {
            assertThat(MyBean.class, allOf(
                    hasValidBeanConstructor(),
                    hasValidGettersAndSetters(),
                    hasValidBeanHashCode(),
                    hasValidBeanEquals(),
                    hasValidBeanToString()
            ));
        }
    
        // Individual, well named tests
    
        @Test
        public void shouldHaveANoArgsConstructor() {
            assertThat(MyBean.class, hasValidBeanConstructor());
        }
    
        @Test
        public void gettersAndSettersShouldWorkForEachProperty() {
            assertThat(MyBean.class, hasValidGettersAndSetters());
        }
    
        @Test
        public void allPropertiesShouldInfluenceHashCode() {
            assertThat(MyBean.class, hasValidBeanHashCode());
        }
    
        @Test
        public void allPropertiesShouldBeComparedDuringEquals() {
            assertThat(MyBean.class, hasValidBeanEquals());
        }
    
        @Test
        public void allPropertiesShouldBeRepresentedInToStringOutput() {
            assertThat(MyBean.class, hasValidBeanToString());
        }
    
    }

Testing the No-Args Constructor

Ensures a bean has a working no-args constructor.

assertThat(BeanToTest.class, hasValidBeanConstructor());

Testing Getters and Setters

Matchers for ensuring what is stored using a setter is what is obtained using the related getter.

Ensure all properties on the bean have working getters and setters.

assertThat(BeanToTest.class, hasValidGettersAndSetters());

Ensure that the property named testOnlyThisProperty has a working getter and setter.

assertThat(BeanToTest.class, hasValidGettersAndSettersFor("testOnlyThisProperty"));

Ensure that all properties on the bean except the property named dontTestPropertyWithThisName has working getters and setters.

assertThat(BeanToTest.class, hasValidGettersAndSettersExcluding("dontTestPropertyWithThisName"));

These matchers test a bean instance.

assertThat(new BeanToTest(), isABeanWithValidGettersAndSetters());

assertThat(new BeanToTest(), isABeanWithValidGettersAndSettersFor("testOnlyThisProperty"));

assertThat(new BeanToTest(), isABeanWithValidGettersAndSettersExcluding("dontTestPropertyWithThisName"));

Testing the hashCode Method

Matchers for ensuring properties influence the generated hash code. This is tested by setting the property with one value and comparing the generated hash code with that produced when the property is set with a different value. If the values differ we infer the hash code is correctly influenced by the property.

Ensure that all properties on the bean influence the produced hash code.

assertThat(BeanToTest.class, hasValidBeanHashCode());

Ensure that the property named propertyInfluencingHashCode influences the produced hash code.

assertThat(BeanToTest.class, hasValidBeanHashCodeFor("propertyInfluencingHashCode"));

Ensure that all properties on the bean except the property named propertyNotInfluencingHashCode influences the produced hash code.

assertThat(BeanToTest.class, hasValidBeanHashCodeExcluding("propertyNotInfluencingHashCode"));

Testing the equals Method

Matchers for ensuring properties are compared during the equals operation. Ensure the method accounts for the same instance, a null instance, instance of differing type and null properties.

Ensure all properties on the bean are compared during the equals method.

assertThat(BeanToTest.class, hasValidBeanEquals());

Ensure the property named testOnlyThisProperty on the bean is compared during the equals method.

assertThat(BeanToTest.class, hasValidBeanEqualsFor("testOnlyThisProperty"));

Ensure all the properties on the bean is compared during the equals method except the property named dontTestPropertyWithThisName.

assertThat(BeanToTest.class, hasValidBeanEqualsExcluding("dontTestPropertyWithThisName"));

Testing the toString Method

Matchers for ensuring the bean class name and properties are included in toString output.

Ensure all properties on the bean are included in the string value.

assertThat(BeanToTest.class, hasValidBeanToString());

Ensure the string value includes includes the property named propertyInToString. Any other properties on the bean are not tested.

assertThat(BeanToTest.class, hasValidBeanToStringFor("propertyInToString"));

Ensure the string value includes all properties on the bean except the property named propertyNotInToString.

assertThat(BeanToTest.class, hasValidBeanToStringExcluding("propertyNotInToString"));

Generating Property Values

The Bean Matchers library generates values to populate beans while performing various tests. Out of the box Bean Matchers will generate random values for properties of primitive, array and enum type. It will delegate to Mockito to create a mock for non-final types. For final types, one can implement and register a ValueGenerator to generate random values.

For example say we have defined a value type:

public final class MyCustomValueType {
    private final String value;

    public MyCustomValueType(String value) {
        this.value = value;
    }
    ...
}

We have a bean with a property of our value type:

public class MyBean {
    private MyCustomValueType property;

    public MyCustomValueType getProperty() {
        return property;
    }

    public void setProperty(MyCustomValueType property) {
        this.property = property;
    }
    ...
}

To test this bean we need to register a ValueGenerator that can generate random values to populate the bean with:

BeanMatchers.registerValueGenerator(new ValueGenerator<MyCustomValueType>() {
        public MyCustomValueType generate() {
            return new MyCustomValueType(StringUtils.randomString());
        }
    }, MyCustomValueType.class);