Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ISSUE 2629] Improve readability of containsExactly #2638

Conversation

Giovds
Copy link
Contributor

@Giovds Giovds commented Jun 1, 2022

Removes elementsDifferAtIndex() from assertContainsExactly() and re-use
shouldContainExactlyWithDiffAssertionError() in order to show the actual
and expected sets entirely. Making the differencesFound() check unnecessary.

It also introduces a new shouldContainExactly() and checks for both
the missing and unexpected diffs to be empty. Otherwise cases where the
actual and expected only differ in order, result into logging of missing
elements - which there are none.

Check List:

Following the contributing guidelines will make it easier for us to review and accept your PR.

throw shouldContainExactlyWithDiffAssertionError(diff, actual, values, info);
}
throw failures.failure(info, elementsDifferAtIndex(actualAsList.get(i), values[i], i, comparisonStrategy));
throw shouldContainExactlyWithDiffAssertionError(diff, actual, values, info);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to include the first index of the diff elements into the message as well?

+ "Expecting actual:%n"
+ " [\"Yoda\", \"Han\", \"Luke\", \"Anakin\"]%n"
+ "to contain exactly (and in same order):%n"
+ " [\"Yoda\", \"Luke\", \"Han\", \"Anakin\"]%n"));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what would be more helpful here in addition to this description is to have the list of mismatches, each mismatch showing the index, the actual element value and the expected element value.

On the example above we could add

but there were differences at these indexes:
- index 1: actual element "Han" but expected was "Luke"
- index 2: actual element "Luke" but expected was "Han"

or

but there were differences at these indexes:
- element at index 1: expected "Han" but was "Luke"
- element at index 2: expected "Luke" but was "Han"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer option 2, WDYT?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid the list of mismatches could be huge (e.g. both lists like 1000 elements and they are in the reverse order), so there should be a hard limit on the number of printed mismatches

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Option 3:

@@ -1,4 +1,4 @@
 Yoda
-Han
 Luke
+Han
 Anakin

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do like the idea of showing (some) indexes, since it may not be as easy to see the differences at a first glance, but I didn't want to differ to much from the original suggestion in the issue.

A couple of questions arise:
In the case actual and expected are equal but not in order, you would show 2 indexes per mismatch which might be too verbose? Does it only count for equal but unorder comparisons, or do we and how would we want to handle other cases like indexes of unexpected and/or missing elements? Should we consider indexes on almost equal cases like [1, 2, 3] vs [1, 2, 4, 3] or could it be too complex?

Wouldn't almost all options be big and perhaps unreadable if the lists contain lots of elements? Option 3 would still add 2 lines per mismatch, resulting in a long list where you would have to scroll a while and without color differences to support the - and + signs it might be difficult to spot the differences if they are 10 elements apart? I'd think the creator of the unit test should consider smaller data sets to prove the functionality is working. Ordering a set of 10 elements would be as good of a test as ordering 1000 elements, unless you are testing performance in which case you wouldn't look at the sets itself, but the time it took?

Do note
The current implementation of Iterables#assertContainsExactly() throws a failure at the first difference it has found, after which it will only remember the missing and unexpected elements without any other information. You might currently not even know anything if the actual and expected are of not the same length. So I'm not sure what the impact of such a change will be, I'd have to look into that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was playing around with the amount of indexes to display yesterday and the MAX_ELEMENTS_FOR_PRINTING is a lot indeed. The first 10 to 50 seems reasonable to me. It could be useful feedback to display something along the lines:

but there were differences at these indexes:
  element at index 0: expected "Luke" but was "Han"
  ...
  element at index 9: expected "Anakin" but was "Leia"
Only showing the first 10 mismatches 

WDYT?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What output would you suggest for the following call assertThat(Arrays.asList(10, 1, 2, 3, 4, 5, 6, 7, 8, 9)).containsExactly(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); ?
I guess displaying all the indices as mismatching won't be that helpful.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Giovds LGTM, maybe we should move Only showing the first 10 mismatches before showing the indexes to be sure users will see it (I'm fine with it at the end too, it's just a suggestion)

but there were differences at these indexes (only showing the first 10 mismatches):
  element at index 0: expected "Luke" but was "Han"
  ...
  element at index 9: expected "Anakin" but was "Leia"

If we have less than 10 mismatches, no need to mention only showing the first 10 mismatches

this is a bit of a contrived example @vlsi, I feel the proposed error message is still helpful enough in this case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm also happy to increase to 50 mismatches by default

Copy link
Contributor

@vlsi vlsi Jun 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you mean the example is contrieved? If the use-case is to assert elements in a strict order, then failure cases would likely be "almost matching" like I show here. There was almost an exact match, except the last element is misplaced.

If all the elements are completely shuffled, then there's no way to briefly describe the mismatch. However, if the elements almost match, then AssertJ could help the user to understand the mismatch

@Giovds
Copy link
Contributor Author

Giovds commented Jun 7, 2022

I'm not sure about this approach, but I'd like to hear your thoughts on it!

@Giovds Giovds force-pushed the issue-2629-improve-readability-of-contains-exactly branch from 1005feb to d6f1d90 Compare June 29, 2022 19:34
@joel-costigliola
Copy link
Member

@Giovds is your PR ready for a review?

@Giovds
Copy link
Contributor Author

Giovds commented Jul 3, 2022

@Giovds is your PR ready for a review?

@joel-costigliola Yes, that would be great!

Removes elementsDifferAtIndex() from assertContainsExactly() and re-use
shouldContainExactlyWithDiffAssertionError() in order to show the actual
and expected sets entirely. Making the differencesFound() check unnecessary.

It also introduces a new shouldContainExactly() and checks for both
the missing and unexpected diffs to be empty. Otherwise cases where the
actual and expected only differ in order, result into logging of missing
elements - which there are none.
Introduces an IndexedDiff to keep track of the diff at an index. If the
lists are of the same length and contain the same elements, but are in
not in the same order, print the indices - limited to 50 - where a
mismatch occurred.
@Giovds Giovds force-pushed the issue-2629-improve-readability-of-contains-exactly branch from d6f1d90 to 4ba9631 Compare July 13, 2022 19:16
@joel-costigliola
Copy link
Member

Integrated in 41179e5 thanks @Giovds!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Display Improve readability of containsExactly when the order of elements does not match
3 participants