1

I have a class Something:

public class Something {
   public String a;
   public String b;
}

Suppose I can't write equals or compare method in class Something.

My test:

Set<Something> aSet;
Set<Something> otherSet;

assertEquals(aSet, otherSet);//Fails because it only compares references of elements and does not perform a deep comparision field by field

Is there any way to assert if both sets are equals comparing elements field by field (without writing equals method in Something class)?

GhostCat
  • 137,827
  • 25
  • 176
  • 248
italktothewind
  • 1,950
  • 2
  • 28
  • 55
  • You can use a TreeSet with a custom comparator. – shmosel Feb 02 '18 at 22:12
  • This SO question also looks promising: https://stackoverflow.com/questions/5204082/is-it-possible-in-java-make-something-like-comparator-but-for-implementing-custo – markspace Feb 02 '18 at 22:27
  • 1
    Please use only those tags that are really relevant to your question. Your question has **no** relation whatsoever to mocking frameworks! – GhostCat Feb 05 '18 at 15:16
  • Well, what's the point in using a set when you don't have proper equals/hashcode methods in the class? Is there really "something" that adds instances multiple times? – Tom Feb 05 '18 at 15:18

3 Answers3

3

Give a try to AssertJ, it provides a way to compare element field by field recursively, example:

// the Dude class does not override equals
Dude jon = new Dude("Jon", 1.2);
Dude sam = new Dude("Sam", 1.3);
jon.friend = sam;
sam.friend = jon;

Dude jonClone = new Dude("Jon", 1.2);
Dude samClone = new Dude("Sam", 1.3);
jonClone.friend = samClone;
samClone.friend = jonClone;

assertThat(asList(jon, sam)).usingRecursiveFieldByFieldElementComparator()
                            .contains(jonClone, samClone);

Another possibility is to compare collections using a specific element comparator so SomethingComparator in your case, this requires a bit more work than the first option but you have full control of the comparison.

Hope it helps!

Joel Costigliola
  • 6,308
  • 27
  • 35
  • I chose this because is correct and really simple and fluent. It doesn't make sense to add code to classes only for testing. Thanks. – italktothewind Feb 05 '18 at 19:58
1

You can use Hamcrest Library and do

assertThat( aSet, both(everyItem(isIn(otherSet))).and(containsInAnyOrder(aSet)));
pvpkiran
  • 25,582
  • 8
  • 87
  • 134
0

I had the similar situation when I couldn't implement equals/hashCode in the legacy code.

Let me share a solution based on the wrapper pattern. You wrap your legacy class and implement equals/hashCode there. In your tests you create a sets of wrapped objects and test it by regular way.

public class SomethingTest {
    class SomethingWrapper {
        private final Something value;

        SomethingWrapper(Something value) {
            this.value = value;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;

            if (o == null || getClass() != o.getClass()) return false;

            SomethingWrapper that = (SomethingWrapper) o;

            return new EqualsBuilder()
                    .append(value.a, that.value.a)
                    .append(value.b, that.value.b)
                    .isEquals();
        }

        @Override
        public int hashCode() {
            return new HashCodeBuilder(17, 37)
                    .append(value.a)
                    .append(value.b)
                    .toHashCode();
        }
    }

    @Test
    public void compareSomethingSetsWithoutEquals() {
        final Set<Something> originalA = new HashSet<>();
        originalA.add(new Something("a1", "b1"));
        originalA.add(new Something("a2", "b2"));

        final Set<Something> originalB = new HashSet<>();
        originalB.add(new Something("a1", "b1"));
        originalB.add(new Something("a2", "b2"));

        final Set<SomethingWrapper> aWrappedSetA =
                originalA.stream().map(SomethingWrapper::new).collect(Collectors.toSet());

        final Set<SomethingWrapper> aWrappedSetB =
                originalB.stream().map(SomethingWrapper::new).collect(Collectors.toSet());

        assertEquals(aWrappedSetA, aWrappedSetB);
    }
}
Dmytro Maslenko
  • 2,247
  • 9
  • 16