With EqualsVerifier, the equals () test was instant

Introduction

If you want to check class equivalence in Java, you need to implement ʻequals () and hashCode () `properly [^ 1]. Normally, I don't implement it myself, so I think there is no mistake, but I'm worried about not testing it.

When I was looking for an efficient method, I found a library called EqualsVerifier [].

Installation

Getting Started describes how to set in Maven. For other tools, see Mvn Repository.

How to use

For example, there is the following Name class. These ʻequals () and hashCode () `are automatically generated by IntelliJ IDEA.

import java.util.Objects;

public final class Name {
    private final String name;

    public Name of(String name) {
        return new Name(name);
    }

    public Name(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Name name1 = (Name) o;
        return Objects.equals(name, name1.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }
}

Here's a test for this (using JUnit 4.12.

import nl.jqno.equalsverifier.EqualsVerifier;
import org.junit.Test;

import java.sql.Timestamp;

public final class EqualsVerifierTest {
    @Test
    public void test_name() {
        EqualsVerifier.forClass(Name.class).verify();
    }
}

Only this. It's easy.

Of course, I don't know if I really tested it, so for example, I test it with the Timestamp [] class, which does not follow the general contract of ʻequals ()`.

EqualsVerifier.forClass(Timestamp.class).verify();

I got the following error.

java.lang.AssertionError: Overloaded: More than one equals method found. Signature should be: public boolean equals(Object obj) For more information, go to: http://www.jqno.nl/equalsverifier/errormessages

If you want to exclude certain fields

It can be found in Ignoring fields, but can be excluded, for example: See the documentation for details.

I think it's better to use transient for myself.

Operating principle

It is written at the bottom of Why, what, how?, but it is roughly as follows. It's a little black magic.

  1. Like the mocking framework, create an instance without calling a constructor.
  2. Use reflection to set the value in the field.
  3. Check if ʻequals () and hashCode () `get the expected results for these.
  4. Examine the signature of the ʻequals () `method to make sure you are using overrides instead of overloads.

in conclusion

I thought it was important to have a feeling of comfort (´ω`)

[^ 1]: Effective Java 2nd Edition See "Item 8 Follow the general contract when overriding equals" and "Item 9 Always override hashCode when overriding equls".

Recommended Posts

With EqualsVerifier, the equals () test was instant
I was addicted to the Spring-Batch test
I rewrote the Rails tutorial test with RSpec
Test the contents of an Excel file with JUnit
Integration Test with Gradle
[Rails] Test with RSpec
Test Nokogiri with Rspec.
Automatically test with Gauge
Load test with JMeter
Unit test with Junit.
The story when the test folder was not created in Rails
What I was addicted to with the Redmine REST API