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

Support parameterized tests at class-level with JUnit5 #9161

Merged
merged 26 commits into from
Dec 19, 2023

Conversation

GianlucaPrincipini
Copy link
Contributor

@GianlucaPrincipini GianlucaPrincipini commented Nov 26, 2023

Feature Request / Improvement

Closes #9210
The goal is to switch all imports to JUni5 imports and to use AssertJ-style assertions.

Since in Junit5 there is no way to parameterize a full test class yet (junit-team/junit5#878),
ParameterizedTestExtension extension class and Parameters / Parameter have been introduced.

@lisirrx
Copy link
Contributor

lisirrx commented Nov 28, 2023

I wonder if this workaround is good enough.
I'm working on #9073 which also encountered the same question.
And there are too many different tests depend on a base TableTestBase which has a constructor with a param that used for class level parameterizing. Many of these test classes also have their own class level parameterizing. 😂 It is very hard to extend these tests by dividing to 2 version

Maybe we need to discuss a plan to deal with this situation.

@nastra Could you like to help us by providing some suggestions?

@RunWith(Parameterized.class)
public class TestDictionaryRowGroupFilter {
/**
* At time of development there's no out of the box way to implement a Parameterized BeforeEach in Junit5.
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think we actually want to create multiple classes for each parameter. I think it would make sense to check how easy/complicated it is to support class-level parameterization with JUnit5 as I know that's not supported by default

Copy link
Contributor

@nastra nastra Nov 28, 2023

Choose a reason for hiding this comment

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

maybe worth exploring whether junit-team/junit5#3157 (comment) would fit here by using a CustomParameterResolver

Choose a reason for hiding this comment

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

Hi @lisirrx @nastra , I met the same problem when I tried to solve #9079. Can we refer to Flink here, introduce a ParameterizedTestExtension?

If you agree with me, I'd like to create a PR to do this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@wanglijie95 @nastra, ParameterizedTestExtension introduced in 4d381f8.
I put it in an util test package, but I think the best idea should be to move these utils in a shared module. Is it better to open a new issue to address it?

Choose a reason for hiding this comment

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

I personally think it is. Put it into a shared module so that it can be used in multiple modules. Besides, I think it's better to add a reference in the ParameterizedTestExtension's doc to indicate it was inspired from Apache Flink. WDYT?

I'd also like to hear @nastra 's thoughts.

Copy link
Contributor

Choose a reason for hiding this comment

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

+1, I think a shared module is better.
BTW, I will check if this approach fits the iceberg-core module.

Copy link
Contributor

Choose a reason for hiding this comment

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

CC: @cgpoh, you might be interested in this

public void createInputFile() throws IOException {
File parquetFile = temp.newFile();
Copy link
Contributor

Choose a reason for hiding this comment

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

I encounter the same case in iceberg-core. I step into the newFile function and find it create a temp file with prefix junit, using File.createTempFile. May be we can use the File.createTempFile directly in our code here?

Copy link
Contributor

Choose a reason for hiding this comment

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

please check other code that was migrated to JUnit5 to see how this was handled

@@ -18,37 +18,13 @@
*/
package org.apache.iceberg.parquet;

import static org.apache.iceberg.avro.AvroSchemaUtil.convert;
Copy link
Contributor

Choose a reason for hiding this comment

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

these shouldn't change

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Solved in 833e9bf.

@nastra
Copy link
Contributor

nastra commented Dec 4, 2023

@GianlucaPrincipini can you please run ./gradlew spotlessApply to fix the formatting?

*
* <p>When use this extension, all tests must be annotated by {@link TestTemplate}.
*/
public class ParameterizedTestExtension implements TestTemplateInvocationContextProvider {
Copy link
Contributor

Choose a reason for hiding this comment

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

this should probably go into the tests under iceberg-api

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Solved in 833e9bf

} catch (Exception e) {
throw new IllegalStateException("Failed to invoke parameter provider", e);
}
assert parameterValues != null;
Copy link
Contributor

Choose a reason for hiding this comment

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

this should be Preconditions.checkState(..)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Solved in 653fec1

import org.junit.runners.Parameterized;

@RunWith(Parameterized.class)
import org.junit.jupiter.api.Assumptions;
Copy link
Contributor

Choose a reason for hiding this comment

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

please use the AssertJ assumtions

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Solved in 833e9bf

}

@TempDir
public Path temp;
Copy link
Contributor

Choose a reason for hiding this comment

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

can be private

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Solved in 6bfb542

@nastra
Copy link
Contributor

nastra commented Dec 5, 2023

@GianlucaPrincipini I would probably rename this PR so that it directly addresses #9210 (because that's what it is doing here). We might also want to convert a few more parameterized tests to using this, just to make sure we're not missing anything

@GianlucaPrincipini
Copy link
Contributor Author

@nastra, sounds ok to me. I will work on migrating some other class in the next few days

@nastra nastra changed the title iceberg-parquet: Switch tests to JUnit5 + AssertJ-style assertions Add JUnit5-equivalent of class-level parameterized tests Dec 6, 2023
@nastra nastra changed the title Add JUnit5-equivalent of class-level parameterized tests Support parameterized tests at class-level with JUnit5 Dec 6, 2023
* @param containedInMessage A String that should be contained by the thrown exception's message
* @param callable A Callable that is expected to throw the exception
*/
public static void assertThrows(
Copy link
Contributor

@nastra nastra Dec 11, 2023

Choose a reason for hiding this comment

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

why is this being added here? It looks like this is from AssertHelpers, which is deprecated. That being said, please revert changes against this file

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 found that those were some duplicate assertThrow in parquet test utils package. I moved these duplicates in 833e9bf without noticing the deprecated ones. I fixed that in ea33322

import java.util.List;
import java.util.function.Function;
import java.util.stream.Stream;
import org.assertj.core.util.Preconditions;
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 actually the wrong import. Should be org.apache.iceberg.relocated.com.google.common.base.Preconditions

public GenericAppenderHelper(
Table table, FileFormat fileFormat, TemporaryFolder tmp, Configuration conf) {
Table table, FileFormat fileFormat, TemporaryFolder tmp, Configuration conf)
Copy link
Contributor

@nastra nastra Dec 12, 2023

Choose a reason for hiding this comment

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

let's roll back these changes and focus only on adding the ParameterizedTestExtension and converting TestDictRowGroupFilter

@nastra
Copy link
Contributor

nastra commented Dec 12, 2023

@GianlucaPrincipini this PR now contains unfortunately more changes than I anticipated, so I would suggest to focus only on adding the ParameterizedTestExtension and converting TestDictRowGroupFilter. All the other changes can then be done in a separate PR.
Also there are a few checkstyle violations, so would be good to fix those as well.

Make sure to run ./gradlew clean build -x test -x integrationTest and ./gradlew spotlessApply locally.

@github-actions github-actions bot removed the MR label Dec 12, 2023
@nastra
Copy link
Contributor

nastra commented Dec 13, 2023

@GianlucaPrincipini the PR still contains more changes than necessary. The scope of this PR is to add the parameterized test extensions and the conversion of TestDictRowGroupFilter. Can you please revert the changes in all the other files? Those can be done in a separate PR once this PR is merged

@nastra
Copy link
Contributor

nastra commented Dec 15, 2023

@Fokko @pvary could you review this one please? Once this is merged we can use it for #9185

@nastra nastra requested a review from Fokko December 15, 2023 15:28
NullPointerException.class,
"Cannot create expression literal from null",
() -> notStartsWith("col", null));
Assertions.assertThatThrownBy(() -> equal("col", null))
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Could we do a static import for this?

@nastra nastra merged commit 892e47c into apache:main Dec 19, 2023
42 checks passed
lisirrx pushed a commit to lisirrx/iceberg that referenced this pull request Jan 4, 2024
geruh pushed a commit to geruh/iceberg that referenced this pull request Jan 26, 2024
rodmeneses added a commit to rodmeneses/iceberg that referenced this pull request Feb 19, 2024
devangjhabakh pushed a commit to cdouglas/iceberg that referenced this pull request Apr 22, 2024
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.

Add JUnit5-equivalent of class-level parameterized tests
5 participants