sta-szek/pojo-tester

"should return different hash codes for non equal objects" seem to be using equal objects

adamsiemion opened this issue · 5 comments

I have a test that from time to time fails in my Jenkins instance, but never failed on my local machine.

It fails with the following message:

Class EntityClass has bad 'hashCode' method implementation.
The hashCode method should return different hash codes for non equal objects.
Current implementation returns same hash codes.
Object:
EntityClass(f1=www.pojo.pl, f2=www.pojo.pl, f3=-4, f4=Fri Mar 10 14:52:19 UTC 2017, f5=www.pojo.pl, f6=www.pojo.pl)
and
EntityClass(f1=www.pojo.pl, f2=www.pojo.pl, f3=-4, f4=Fri Mar 10 14:52:19 UTC 2017, f5=www.pojo.pl, f6=www.pojo.pl)
should have different hash codes:
38708309
and
38708309

Class code:

@Getter
@ToString
@EqualsAndHashCode
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PACKAGE)
public class EntityClass {

    private String f1;
    private String f2;
    private int f3;
    private Date f4;
    private String f5;
    private String f6;
}

and this is my test

assertPojoMethodsFor(EntityClass.class)
        .testing(GETTER, TO_STRING, CONSTRUCTOR, EQUALS, HASH_CODE)
        .areWellImplemented();

I suspect the Date f4 field is the same and it is causing issues.
BTW. Is there a way to change the test (as I cannot change the production code) so that when it fails, a custom message (provided function) is used instead of toString()? Something along these lines:

    assertPojoMethodsFor(EntityClass.class)
            .testing(GETTER, TO_STRING, CONSTRUCTOR, EQUALS, HASH_CODE)
            .areWellImplemented()
            .messageWhenFails((o1, o2) -> "o1 date" + o1.f4 + " and o2 date" + o2.f4);

Thanks for reporting!
As you suggested, the problem is caused by java.util.Date class, as pojo-tester does not know how to change instance of that class to make them different.

The solution is to implement another one field value changer.

In this issue I will add following field value changers to pojo-tester:

  • DateFieldValueChanger (java.util.Date)
  • InstantFieldValueChanger (java.time.Instant)
  • LocalDateFieldValueChanger (java.time.LocalDate)
  • LocalDateTimeFieldValueChanger (java.time.LocalDateTime)
  • LocalTimeFieldValueChanger (java.time.LocalTime)
  • ZonedDateTimeFieldValueChanger (java.time.ZonedDateTime)
  • SqlDateFieldValueChanger (java.sql.Date)

And unfortunately there is no way to define custom message. If you wish so, please report feature request.

Have you got any suggestions?

BTW, for now you can workaround this as follows:

package pl.pojo.tester.issue187;


import org.junit.jupiter.api.Test;
import pl.pojo.tester.internal.field.AbstractFieldValueChanger;
import pl.pojo.tester.internal.field.DefaultFieldValueChanger;

import java.time.Instant;
import java.util.Date;

import static pl.pojo.tester.api.assertion.Assertions.assertPojoMethodsFor;
import static pl.pojo.tester.api.assertion.Method.*;

public class EntityClassPojoTest {

    @Test
    public void Should_Test_Entity_Class() {
        for (int i = 0; i < 10000; i++) {
            final AbstractFieldValueChanger fieldValueChanger = DefaultFieldValueChanger.INSTANCE.attachNext(new DateFieldValueChanger());
            assertPojoMethodsFor(EntityClass.class).testing(GETTER, TO_STRING, CONSTRUCTOR, EQUALS, HASH_CODE)
                                                   .using(fieldValueChanger)
                                                   .areWellImplemented();
        }
    }

    class DateFieldValueChanger extends AbstractFieldValueChanger<Date> {

        @Override
        public boolean areDifferentValues(final Date sourceValue, final Date targetValue) {
            return !sourceValue.equals(targetValue);
        }

        @Override
        protected Date increaseValue(final Date value, final Class<?> type) {
            final Instant nextDay = value.toInstant().plusSeconds(86_400);
            return Date.from(nextDay);
        }

        @Override
        protected boolean canChange(final Class<?> type) {
            return type.equals(Date.class);
        }
    }

}

Great stuff! Thank you for a prompt reply.

@sta-szek Great job, thanks! Quick question, when 0.7.5 will be released?

Due by March 19, 2017