Skip to content

Use a non-deprecated assertThat, and change several test assertions to use assertThat #14518

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

thecoop
Copy link
Contributor

@thecoop thecoop commented Apr 17, 2025

The main reason for this PR is using an un-deprecated assertThat by default. I've also updated a few uses of old-style assertions to use assertThat and Matchers for readability and a more descriptive error message. There's obviously loads more that could be updated; this is a few to start with.

Arrays.stream(c.destDir.listAll())
.collect(Collectors.toSet())
.containsAll(merge.getMergeInfo().files()));
assertFalse(Set.of(c.destDir.listAll()).containsAll(merge.getMergeInfo().files()));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This doesn't easily translate into a matcher, so I've changed to use Set.of to make it a bit more readable

Copy link
Contributor

Choose a reason for hiding this comment

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

I think the previous version was actually more intuitive?

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 don't think so - using a stream from an array to collect into a set, vs just creating a set directly from the array?

Copy link
Contributor

Choose a reason for hiding this comment

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

So, yes, it's all subjective. The previous version had stream methods over multiple lines - to me that read easier compared to the one-liner now.

Copy link
Contributor

@dweiss dweiss left a comment

Choose a reason for hiding this comment

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

Thank you for working on cleaning up tests. I still favor assertj assertions over hamcrest - they seem so much cleaner to me. But let's keep things consistent, no worries. This looks good to me.

@dweiss
Copy link
Contributor

dweiss commented Apr 18, 2025

I'll merge this one later today if there are no objections.

@@ -233,7 +245,7 @@ public void testPositionIncrementMultiFields() throws Exception {
PhraseQuery query = new PhraseQuery("indexed_not_tokenized", "test1", "test2");

ScoreDoc[] hits = searcher.search(query, 1000).scoreDocs;
assertEquals(1, hits.length);
assertThat(hits, arrayWithSize(1));
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 wondering why this is considered an improvement, the previous assert is much more readable

Copy link
Contributor

Choose a reason for hiding this comment

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

I think error messages are better... I haven't been using hamcrest much so I can't tell for sure - assertj definitely provides more informative error messages. I don't mind either way, even though hamcrest's style is confusing to me too.

Copy link
Member

Choose a reason for hiding this comment

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

I guess I'm confused what could be better about the existing error message, it asserts that array's length is 1, and if its something else, you'll see that number.

So... zero benefit, but at the cost of making the code significantly more difficult to read (which is actually very important when trying to debug the tests)

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 prefer the more declarative style of assertThat, and the assertion failure specifies what the problem actually is, rather than 'this singular value is not what is expected'

@dweiss
Copy link
Contributor

dweiss commented Apr 19, 2025

I have taken another look. The one thing I would revert is replacing assertEquals with hamcrest matchers - it is indeed the same functionality, the same output message and more verbose code. Other changes seem more palatable to me - like array containment cleaned up (and this should result in a better error message, should something wrong happen), assertTrue conditions replaced with equality checks (so that values are reported, not just failed assertion).

Comment on lines +113 to +115
assertThat(doc.getFields(), hasSize(10));
doc.removeFields("keyword");
assertEquals(8, doc.getFields().size());
assertThat(doc.getFields(), hasSize(8));
Copy link
Contributor

Choose a reason for hiding this comment

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

This is an example of changes that don't provide any extra value, I think.

@@ -207,7 +219,7 @@ public void testGetValuesForIndexedDocument() throws Exception {

// ensure that queries return expected results without DateFilter first
ScoreDoc[] hits = searcher.search(query, 1000).scoreDocs;
assertEquals(1, hits.length);
assertThat(hits, arrayWithSize(1));
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here. It's more verbose and does the same thing.

Comment on lines +328 to +341
Set<String> seen = new HashSet<>();
StoredFields storedFields = searcher.storedFields();
for (int i = 0; i < 3; i++) {
Document doc2 = storedFields.document(hits[i].doc);
Field f = (Field) doc2.getField("id");
if (f.stringValue().equals("id1")) result |= 1;
else if (f.stringValue().equals("id2")) result |= 2;
else if (f.stringValue().equals("id3")) result |= 4;
else fail("unexpected id field");
switch (f.stringValue()) {
case "id1", "id2", "id3" -> seen.add(f.stringValue());
default -> fail("unexpected id field");
}
}
writer.close();
reader.close();
dir.close();
assertEquals("did not see all IDs", 7, result);
assertThat("did not see all IDs", seen, containsInAnyOrder("id1", "id2", "id3"));
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this could be just assertEquals(seen, Set.of(...)) - this would detect anything extra and check for the occurrence of all ids?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

containsInAnyOrder fails if there are any extra items in the collection.

More generally, assertEquals(..., Set.of()) checks if the value is a Set, which is not actually important here. The collection could be a List and the test would still work. So checking for Set isn't required here for the test to pass, whereas containsInAnyOrder doesn't care about the type of collection used.

Arrays.stream(c.destDir.listAll())
.collect(Collectors.toSet())
.containsAll(merge.getMergeInfo().files()));
assertFalse(Set.of(c.destDir.listAll()).containsAll(merge.getMergeInfo().files()));
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the previous version was actually more intuitive?

Comment on lines +122 to +126
assertThat(parseInt("1"), equalTo(1));
assertThat(parseInt("-10000"), equalTo(-10000));
assertThat(parseInt("1923"), equalTo(1923));
assertThat(parseInt("-1"), equalTo(-1));
assertThat(ArrayUtil.parseInt("foo 1923 bar".toCharArray(), 4, 4), equalTo(1923));
Copy link
Contributor

Choose a reason for hiding this comment

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

This is an example of a potentially better message but what's wrong with assertEquals(a, b)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

assertEquals is ambiguous to what the thing being test is vs the expected value it should have, assertThat is not

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure, true, if you're using it the first time perhaps. :)

@thecoop
Copy link
Contributor Author

thecoop commented Apr 22, 2025

The focus of this PR was to change assertTrue/assertFalse to assertions that gave what was actually wrong. The assertEquals are things I spotted alongside those.

I prefer the assertThat hamcrest matchers over assertEquals because it is unequivocal what the expected value is vs what is being tested, which is not the case with assertEquals, and I think the matcher assertions read better for what the test is checking, especially with more complicated checks such as arrayWithSize(greaterThan(6)). I used hamcrest as that is used more in the codebase than assertj. However, using hamcrest in this way is a personal preference, that can easily be removed from this PR if people disagree.

@dweiss
Copy link
Contributor

dweiss commented Apr 22, 2025

I'm fine with merging this change. I don't mind if the code becomes a bit more verbose because of it. Rob?

@rmuir
Copy link
Member

rmuir commented Apr 23, 2025

my concern wasn't about verbosity: if you are concerned about this, steer clear of java!

instead just keeping "barrier to entry" to understanding the tests low. This includes requiring developer to go and understand a third-party library in order to debug it. But if this is really more natural to most developers, then I'm ok.

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

Successfully merging this pull request may close these issues.

3 participants