Skip to content

Contractual is a set of Java interfaces that define generic test contracts. A JUnit 5 test class can then implement one or more of these test interfaces to inherit test cases that verify that their contract is fulfilled by the class under test.

License

Notifications You must be signed in to change notification settings

redfin/contractual

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

19 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Build Status License

Contractual

Overview

Contractual is a simple Java library of interfaces with default @Test methods for use with JUnit 5. This allows for generic tests to be written and re-used for every class that makes sense for that contract. It can also improve the writing of new classes in the first place. For instance, if you write a new class that overrides the equals method but forget to override the hashCode method, the EqualsContract interface, when applied to the new class's unit test class will fail.

Installation

<dependency>
    <groupId>com.redfin</groupId>
    <artifactId>contractual</artifactId>
    <version>3.0.0</version>
    <scope>test</scope>
</dependency>

Example usage

Say you write a new class Foo that contains a String value. Two Foo instances should be equal only if they both contain the same String. To properly override the equals method you have to make sure that the equals method contract (defined in the Object class) is maintained. You also need to make sure that you override the hashCode method. An example implementation would be:

public class Foo {

    private final String s;

    public Foo(String s) {
        this.s = Objects.requireNonNull(s);
    }

    @Override
    public boolean equals(Object obj) {
        return obj instanceof Foo && s.equals(((Foo)obj).s);
    }

    @Override
    public int hashCode() {
        return s.hashCode();
    }

    // other code specific to Foo
}

When it comes time to write the unit tests for Foo (say in a test class called FooTest) then there would normally be repeated code for each class that overrides the equals method. Contracts, along with JUnit 5, can spare you from repeated that test code (and possibly missing cases). The FooTest could just implement the interface, implement any abstract methods, and then it will inherit the test methods defined in the contract.

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;

@DisplayName("A Foo")
class FooTest implements EqualsContract<Foo> {

    private static final String EQUAL = "hello";
    private static final String NON_EQUAL = "world";

    @Nested
    @DisplayName("satisfies the EqualsContract as")
    class EqualityTest implements EqualsContract<Foo> {

        @Override
        public Foo getInstance() {
            return new Foo(EQUAL);
        }

        @Override
        public Supplier<Foo> getEqualInstanceSupplier() {
            return () -> new Foo(EQUAL);
        }

        @Override
        public Foo getNonEqualInstance() {
            return new Foo(NON_EQUAL);
        }
    }

    // any unit tests specific to Foo
}

About

Contractual is a set of Java interfaces that define generic test contracts. A JUnit 5 test class can then implement one or more of these test interfaces to inherit test cases that verify that their contract is fulfilled by the class under test.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages