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

Migrate all tests to JUnit5 #9796

Merged
merged 19 commits into from
Aug 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
245248c
build(test): remove JUnit 4 from POM, upgrade to JUnit 5.10
poikilotherm Aug 18, 2023
2ca734e
build(test): migrate all imports from JUnit 4 to JUnit 5 #9782
poikilotherm Aug 18, 2023
955bc36
build(test): migrate Before, After and Ignore to JUnit 5 equivalents …
poikilotherm Aug 18, 2023
930950a
build(test): migrate JUnit 4 Categories to JUnit 5 Tags, adapt Maven …
poikilotherm Aug 18, 2023
889a857
build(test): migrate JUnit4 @runWith annotations to JUnit5 or delete …
poikilotherm Aug 18, 2023
fbd7077
build(test): migrate exception testing from JUnit4 to JUnit5 style
poikilotherm Aug 18, 2023
6ddc8db
build(test): switch to static imports for assertions everywhere and s…
poikilotherm Aug 18, 2023
d2044f1
build(test): migrate JUnit4 parameterized tests and theories to JUnit…
poikilotherm Aug 18, 2023
ddd0dcc
build(test): migrate JUnit4 temp dir rules to JUnit5 @TempDir #9782
poikilotherm Aug 18, 2023
9b8dc3d
build(test): migrate JUnit4 assertion arguments order to JUnit5 style…
poikilotherm Aug 18, 2023
0d8e597
Merge branch 'develop' into 9782-migrate-junit5
poikilotherm Aug 18, 2023
7587b95
doc(test): migrate testing guide to JUnit5 #9782
poikilotherm Aug 18, 2023
3ecca86
build(test): fix overlooked assertEquals arg flips in HarvestingClien…
poikilotherm Aug 21, 2023
db07e94
doc(test): add release note about JUnit5 migration #9782
poikilotherm Aug 21, 2023
3f62e22
Merge branch 'develop' into 9782-migrate-junit5
poikilotherm Aug 21, 2023
0b91700
build(parent): add Maven enforcer rules to ban JUnit 4 #9782
poikilotherm Aug 21, 2023
d6c3f7a
build(parent): enforce Java 17 in use or fail
poikilotherm Aug 21, 2023
9410880
build(deps,test): upgrade to Mockito 5.4.0 #9782
poikilotherm Aug 22, 2023
494624b
chore(test): migrate tests to Mockito 5 API #9782
poikilotherm Aug 22, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions doc/release-notes/9782-juni5-transition.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Migrating all test to JUnit 5
With this release, we transition all of our test cases (see `src/test/`) to use JUnit 5 only.
Moving forward from JUnit 4 will allow writing tests in more concise and easier ways.
The tests themselves have not been altered, but updated to match JUnit 5 ways.
They have not been extended or dropped coverage; this is mostly a preparation of things to come in the future.
If you are writing tests in JUnit 4 in your feature branches, you need to migrate.
The development guides section of testing has been updated as well.
35 changes: 21 additions & 14 deletions doc/sphinx-guides/source/developers/testing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,14 @@ Writing Unit Tests with JUnit
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

We are aware that there are newer testing tools such as TestNG, but we use `JUnit <http://junit.org>`_ because it's tried and true.
We support both (legacy) JUnit 4.x tests (forming the majority of our tests) and
newer JUnit 5 based testing.
We support JUnit 5 based testing and require new tests written with it.
(Since Dataverse 6.0, we migrated all of our tests formerly based on JUnit 4.)

NOTE: When adding new tests, you should give JUnit 5 a go instead of adding more dependencies to JUnit 4.x.

If writing tests is new to you, poke around existing unit tests which all end in ``Test.java`` and live under ``src/test``. Each test is annotated with ``@Test`` and should have at least one assertion which specifies the expected result. In Netbeans, you can run all the tests in it by clicking "Run" -> "Test File". From the test file, you should be able to navigate to the code that's being tested by right-clicking on the file and clicking "Navigate" -> "Go to Test/Tested class". Likewise, from the code, you should be able to use the same "Navigate" menu to go to the tests.
If writing tests is new to you, poke around existing unit tests which all end in ``Test.java`` and live under ``src/test``.
Each test is annotated with ``@Test`` and should have at least one assertion which specifies the expected result.
In Netbeans, you can run all the tests in it by clicking "Run" -> "Test File".
From the test file, you should be able to navigate to the code that's being tested by right-clicking on the file and clicking "Navigate" -> "Go to Test/Tested class".
Likewise, from the code, you should be able to use the same "Navigate" menu to go to the tests.

NOTE: Please remember when writing tests checking possibly localized outputs to check against ``en_US.UTF-8`` and ``UTC``
l10n strings!
Expand All @@ -62,22 +64,24 @@ Refactoring Code to Make It Unit-Testable

Existing code is not necessarily written in a way that lends itself to easy testing. Generally speaking, it is difficult to write unit tests for both JSF "backing" beans (which end in ``Page.java``) and "service" beans (which end in ``Service.java``) because they require the database to be running in order to test them. If service beans can be exercised via API they can be tested with integration tests (described below) but a good technique for making the logic testable it to move code to "util beans" (which end in ``Util.java``) that operate on Plain Old Java Objects (POJOs). ``PrivateUrlUtil.java`` is a good example of moving logic from ``PrivateUrlServiceBean.java`` to a "util" bean to make the code testable.

Parameterized Tests and JUnit Theories
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Parameterized Tests
^^^^^^^^^^^^^^^^^^^

Often times you will want to test a method multiple times with similar values.
In order to avoid test bloat (writing a test for every data combination),
JUnit offers Data-driven unit tests. This allows a test to be run for each set
of defined data values.

JUnit 4 uses ``Parameterized.class`` and ``Theories.class``. For reference, take a look at issue https://github.com/IQSS/dataverse/issues/5619.

JUnit 5 doesn't offer theories (see `jqwik <https://jqwik.net>`_ for this), but
greatly extended parameterized testing. Some guidance how to write those:
JUnit 5 offers great parameterized testing. Some guidance how to write those:

- https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests
- https://www.baeldung.com/parameterized-tests-junit-5
- https://blog.codefx.org/libraries/junit-5-parameterized-tests/
- See also some examples in our codebase.
- See also many examples in our codebase.

Note that JUnit 5 also offers support for custom test parameter resolvers. This enables keeping tests cleaner,
as preparation might happen within some extension and the test code is more focused on the actual testing.
See https://junit.org/junit5/docs/current/user-guide/#extensions-parameter-resolution for more information.

JUnit 5 Test Helper Extensions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -116,11 +120,14 @@ In addition, there is a writeup on "The Testable Command" at https://github.com/
Running Non-Essential (Excluded) Unit Tests
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

You should be aware that some unit tests have been deemed "non-essential" and have been annotated with ``@Category(NonEssentialTests.class)`` and are excluded from the "dev" Maven profile, which is the default profile. All unit tests (that have not been annotated with ``@Ignore``), including these non-essential tests, are run from continuous integration systems such as Jenkins and GitHub Actions with the following ``mvn`` command that invokes a non-default profile:
You should be aware that some unit tests have been deemed "non-essential" and have been annotated with ``@Tag(Tags.NOT_ESSENTIAL_UNITTESTS)`` and are excluded from the "dev" Maven profile, which is the default profile.
All unit tests (that have not been annotated with ``@Disable``), including these non-essential tests, are run from continuous integration systems such as Jenkins and GitHub Actions with the following ``mvn`` command that invokes a non-default profile:

``mvn test -P all-unit-tests``

Generally speaking, unit tests have been flagged as non-essential because they are slow or because they require an Internet connection. You should not feel obligated to run these tests continuously but you can use the ``mvn`` command above to run them. To iterate on the unit test in Netbeans and execute it with "Run -> Test File", you must temporarily comment out the annotation flagging the test as non-essential.
Generally speaking, unit tests have been flagged as non-essential because they are slow or because they require an Internet connection.
You should not feel obligated to run these tests continuously but you can use the ``mvn`` command above to run them.
To iterate on the unit test in Netbeans and execute it with "Run -> Test File", you must temporarily comment out the annotation flagging the test as non-essential.

Integration Tests
-----------------
Expand Down
55 changes: 50 additions & 5 deletions modules/dataverse-parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,9 @@
<!-- Testing dependencies -->
<testcontainers.version>1.15.0</testcontainers.version>
<smallrye-mpconfig.version>2.10.1</smallrye-mpconfig.version>

<junit.version>4.13.1</junit.version>
<junit.jupiter.version>5.7.0</junit.jupiter.version>
<junit.vintage.version>${junit.jupiter.version}</junit.vintage.version>
<mockito.version>2.28.2</mockito.version>

<junit.jupiter.version>5.10.0</junit.jupiter.version>
<mockito.version>5.4.0</mockito.version>

<checkstyle.version>9.3</checkstyle.version>

Expand All @@ -193,6 +191,7 @@
<maven-source-plugin.version>3.2.1</maven-source-plugin.version>
<maven-javadoc-plugin.version>3.4.1</maven-javadoc-plugin.version>
<maven-flatten-plugin.version>1.3.0</maven-flatten-plugin.version>
<maven-enforcer-plugin.version>3.3.0</maven-enforcer-plugin.version>

<maven-checkstyle-plugin.version>3.1.2</maven-checkstyle-plugin.version>
<nexus-staging-plugin.version>1.6.13</nexus-staging-plugin.version>
Expand Down Expand Up @@ -255,6 +254,11 @@
<artifactId>maven-failsafe-plugin</artifactId>
<version>${maven-failsafe-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>${maven-enforcer-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
Expand Down Expand Up @@ -314,6 +318,47 @@
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>
<execution>
<id>no-junit4</id>
<phase>generate-test-resources</phase>
<goals>
<goal>enforce</goal>
</goals>
<configuration>
<rules>
<bannedDependencies>
<excludes>
<exclude>junit:junit:*:*:test</exclude>
<exclude>org.junit:junit:*:*:test</exclude>
<exclude>org.junit.vintage:*:*:*:test</exclude>
</excludes>
</bannedDependencies>
</rules>
</configuration>
</execution>
<execution>
<id>general-reqs</id>
<goals>
<goal>enforce</goal>
</goals>
<phase>initialize</phase>
<configuration>
<rules>
<banDuplicatePomDependencyVersions/>
<requireJavaVersion>
<version>[${target.java.version}.0,)</version>
</requireJavaVersion>
</rules>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>

<!--Maven checks for dependencies from these repos in the order shown in the pom.xml
Expand Down
26 changes: 13 additions & 13 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,12 @@
<artifactId>ezid</artifactId>
<version>1.0.0</version>
<type>jar</type>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
Expand Down Expand Up @@ -542,18 +548,6 @@
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>${junit.vintage.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
Expand Down Expand Up @@ -594,6 +588,12 @@
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
Expand Down Expand Up @@ -781,7 +781,7 @@
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<testsToExclude>edu.harvard.iq.dataverse.NonEssentialTests</testsToExclude>
<testsToExclude>not-essential-unittests</testsToExclude>
</properties>
</profile>
<profile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
import java.util.Arrays;
import java.util.List;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import jakarta.persistence.TypedQuery;

import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.Before;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentMatchers;

Expand All @@ -25,7 +24,7 @@ public class AuxiliaryFileServiceBeanTest {
List<String> types;
DataFile dataFile;

@Before
@BeforeEach
public void setup() {
svc = new AuxiliaryFileServiceBean();
svc.em = mock(EntityManager.class);
Expand Down
18 changes: 9 additions & 9 deletions src/test/java/edu/harvard/iq/dataverse/CartTest.java
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
package edu.harvard.iq.dataverse;

import static org.junit.Assert.fail;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.util.List;
import java.util.Map.Entry;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;

public class CartTest {

private Cart cart;
private String title;
private String persistentId;

@Before
@BeforeEach
public void setUp() {
this.cart = new Cart();
this.title = "title";
this.persistentId = "persistentId";
}

@After
@AfterEach
public void tearDwon() {
this.cart = null;
this.title = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
import edu.harvard.iq.dataverse.util.BundleUtil;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.junit.runner.RunWith;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.Arrays;
import java.util.List;
Expand All @@ -19,7 +21,7 @@
*
* @author adaybujeda
*/
@RunWith(MockitoJUnitRunner.class)
@ExtendWith(MockitoExtension.class)
public class DataFileCategoryServiceBeanTest {

@Mock
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package edu.harvard.iq.dataverse;

import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

/**
* Test that the DataFileServiceBean classifies DataFiles correctly.
Expand All @@ -27,7 +28,7 @@ public DataFileServiceBeanTest() {
private DataFileServiceBean dataFileServiceBean;


@Before
@BeforeEach
public void setUp() {
fileWoContentType = createDataFile(null);
fileWithBogusContentType = createDataFile("foo/bar");
Expand Down
54 changes: 17 additions & 37 deletions src/test/java/edu/harvard/iq/dataverse/DatasetAuthorTest.java
Original file line number Diff line number Diff line change
@@ -1,46 +1,26 @@
package edu.harvard.iq.dataverse;

import static org.junit.Assert.assertEquals;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

import java.util.Arrays;
import java.util.Collection;
import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)
public class DatasetAuthorTest {

public String idType;
public String idValue;
public String expectedIdentifierAsUrl;

public DatasetAuthorTest(String idType, String idValue, String expectedIdentifierAsUrl) {
this.idType = idType;
this.idValue = idValue;
this.expectedIdentifierAsUrl = expectedIdentifierAsUrl;
}

@Parameters
public static Collection<String[]> parameters() {
return Arrays.asList(new String[][] {
{ "ORCID", "0000-0002-1825-0097", "https://orcid.org/0000-0002-1825-0097" },
{ "ISNI", "0000000121032683", "http://www.isni.org/isni/0000000121032683"},
{ "LCNA", "n82058243", "http://id.loc.gov/authorities/names/n82058243" },
{ "VIAF", "172389567", "https://viaf.org/viaf/172389567" },
{ "GND", "4079154-3", "https://d-nb.info/gnd/4079154-3" },
{ "ResearcherID", "634082", "https://publons.com/researcher/634082/" },
{ "ResearcherID", "AAW-9289-2021", "https://publons.com/researcher/AAW-9289-2021/" },
{ "ResearcherID", "J-9733-2013", "https://publons.com/researcher/J-9733-2013/" },
{ "ScopusID", "6602344670", "https://www.scopus.com/authid/detail.uri?authorId=6602344670" },
{ null, null, null, },
});
}

@Test
public void getIdentifierAsUrl() {
@ParameterizedTest
@CsvSource(value = {
"ORCID,0000-0002-1825-0097,https://orcid.org/0000-0002-1825-0097",
"ISNI,0000000121032683,http://www.isni.org/isni/0000000121032683",
"LCNA,n82058243,http://id.loc.gov/authorities/names/n82058243",
"VIAF,172389567,https://viaf.org/viaf/172389567",
"GND,4079154-3,https://d-nb.info/gnd/4079154-3",
"ResearcherID,634082,https://publons.com/researcher/634082/",
"ResearcherID,AAW-9289-2021,https://publons.com/researcher/AAW-9289-2021/",
"ResearcherID,J-9733-2013,https://publons.com/researcher/J-9733-2013/",
"ScopusID,6602344670,https://www.scopus.com/authid/detail.uri?authorId=6602344670",
"NULL,NULL,NULL"
}, nullValues = "NULL")
void getIdentifierAsUrl(String idType, String idValue, String expectedIdentifierAsUrl) {
DatasetAuthor datasetAuthor = new DatasetAuthor();
if (idType !=null && idValue != null) {
datasetAuthor.setIdType(idType);
Expand Down
Loading
Loading