Skip to content

Commit cea29ef

Browse files
committed
Migrate remaining JUnit4-style tests in lib to JUnit Jupiter
1 parent cb923f0 commit cea29ef

6 files changed

Lines changed: 69 additions & 102 deletions

File tree

lib/build.gradle

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ dependencies {
2121
testImplementation('org.mockito:mockito-core:5.14.2')
2222
testImplementation('com.google.truth:truth:1.4.4')
2323
testRuntimeOnly('org.junit.platform:junit-platform-launcher')
24-
testRuntimeOnly('org.junit.vintage:junit-vintage-engine')
25-
testImplementation 'junit:junit:4.13.2'
2624
testImplementation project(':testing')
2725
compileOnly 'com.google.auto.value:auto-value-annotations:1.11.0'
2826
annotationProcessor 'com.google.auto.value:auto-value:1.11.0'
@@ -31,10 +29,8 @@ dependencies {
3129
// the magic line that makes tests work :)
3230
wpi.java.configureTestTasks(test)
3331

34-
tasks.named('test') {
35-
// Support running both JUnit Vintage and JUnit Jupiter tests
32+
test {
3633
useJUnitPlatform()
37-
systemProperty 'junit.jupiter.extensions.autodetection.enabled', 'true'
3834
}
3935

4036
publishing {

lib/src/test/java/com/team2813/lib2813/preferences/IsolatedPreferences.java

Lines changed: 5 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,39 +15,9 @@
1515
*/
1616
package com.team2813.lib2813.preferences;
1717

18-
import edu.wpi.first.networktables.NetworkTable;
19-
import edu.wpi.first.networktables.NetworkTableInstance;
20-
import edu.wpi.first.wpilibj.Preferences;
21-
import org.junit.rules.ExternalResource;
22-
23-
/**
24-
* A JUnit rule that ensures that changes to preferences done by a test are not leaked out to other
25-
* tests.
26-
*/
27-
final class IsolatedPreferences extends ExternalResource {
28-
private NetworkTableInstance tempInstance;
29-
30-
/** Gets the {@link NetworkTable} that contains the preference values. */
31-
public NetworkTable getPreferencesTable() {
32-
return tempInstance.getTable("Preferences");
33-
}
34-
35-
@Override
36-
protected void before() {
37-
NetworkTableInstance.getDefault();
38-
tempInstance = NetworkTableInstance.create();
39-
tempInstance.startLocal();
40-
Preferences.setNetworkTableInstance(tempInstance);
41-
}
42-
43-
@Override
44-
protected void after() {
45-
Preferences.setNetworkTableInstance(NetworkTableInstance.getDefault());
46-
if (!tempInstance.waitForListenerQueue(.2)) {
47-
System.err.println(
48-
"Timed out waiting for the NetworkTableInstance listener queue to empty (waited 200ms);"
49-
+ " JVM may crash");
50-
}
51-
tempInstance.close();
52-
}
18+
// TODO: Remove this file.
19+
// Initial attempts at deletion caused exceptions in :lib:spotlessJava,
20+
// possibly due to the Copyright header check.
21+
final class IsolatedPreferences {
22+
private IsolatedPreferences() {}
5323
}

lib/src/test/java/com/team2813/lib2813/preferences/PersistedConfigurationTest.java

Lines changed: 55 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -19,59 +19,70 @@
1919
import static com.google.common.truth.Truth.assertWithMessage;
2020
import static com.team2813.lib2813.preferences.PersistedConfiguration.REGISTERED_CLASSES_NETWORK_TABLE_KEY;
2121
import static java.util.stream.Collectors.toMap;
22-
import static org.junit.Assert.assertThrows;
22+
import static org.junit.jupiter.api.Assertions.assertAll;
23+
import static org.junit.jupiter.api.Assertions.assertThrows;
24+
import static org.junit.jupiter.api.Assertions.fail;
2325

26+
import com.team2813.lib2813.testing.junit.jupiter.IsolatedNetworkTablesExtension;
2427
import edu.wpi.first.networktables.NetworkTable;
2528
import edu.wpi.first.networktables.NetworkTableEntry;
29+
import edu.wpi.first.networktables.NetworkTableInstance;
2630
import edu.wpi.first.networktables.NetworkTableType;
2731
import edu.wpi.first.networktables.Topic;
2832
import edu.wpi.first.wpilibj.DataLogManager;
2933
import edu.wpi.first.wpilibj.Preferences;
34+
import java.util.ArrayList;
3035
import java.util.HashSet;
36+
import java.util.List;
3137
import java.util.Map;
3238
import java.util.Set;
3339
import java.util.function.*;
34-
import org.junit.After;
35-
import org.junit.Before;
36-
import org.junit.Rule;
37-
import org.junit.Test;
38-
import org.junit.experimental.runners.Enclosed;
39-
import org.junit.rules.ErrorCollector;
40-
import org.junit.runner.RunWith;
41-
import org.junit.runners.Parameterized;
42-
import org.junit.runners.Parameterized.Parameters;
40+
import org.junit.jupiter.api.AfterEach;
41+
import org.junit.jupiter.api.BeforeEach;
42+
import org.junit.jupiter.api.Nested;
43+
import org.junit.jupiter.api.Test;
44+
import org.junit.jupiter.api.extension.ExtendWith;
45+
import org.junit.jupiter.api.function.Executable;
46+
import org.junit.jupiter.params.ParameterizedClass;
47+
import org.junit.jupiter.params.provider.ValueSource;
4348

4449
/** Tests for {@link PersistedConfiguration}. */
45-
@RunWith(Enclosed.class)
4650
public final class PersistedConfigurationTest {
4751
private static final double EPSILON = 0.001;
4852

4953
/** Base class for all nested classes of {@link PersistedConfigurationTest}. */
50-
abstract static class PreferencesRegistryTestCase<T extends Record> {
54+
@Nested
55+
@ExtendWith(IsolatedNetworkTablesExtension.class)
56+
abstract class PreferencesRegistryTestCase<T extends Record> {
57+
private final List<Executable> collectedErrors = new ArrayList<>();
5158
private final String preferenceName;
5259
private final Class<T> recordClass;
53-
54-
@Rule public final IsolatedPreferences isolatedPreferences = new IsolatedPreferences();
55-
@Rule public final ErrorCollector errorCollector = new ErrorCollector();
60+
private NetworkTableInstance ntInstance;
61+
private NetworkTable preferencesTable;
5662

5763
protected PreferencesRegistryTestCase(String preferenceName, Class<T> recordClass) {
5864
this.preferenceName = preferenceName;
5965
this.recordClass = recordClass;
6066
}
6167

62-
@Before
68+
@BeforeEach
69+
public final void injectNetworkTableInstance(NetworkTableInstance ntInstance) {
70+
this.ntInstance = ntInstance;
71+
preferencesTable = ntInstance.getTable("Preferences");
72+
}
73+
74+
@BeforeEach
6375
public final void setTestGlobals() {
6476
PersistedConfiguration.throwExceptions = true;
6577
PersistedConfiguration.errorReporter =
66-
message ->
67-
errorCollector.addError(
68-
new AssertionError("Unexpected warning: \"" + message + "\""));
78+
message -> collectedErrors.add(() -> fail("Unexpected warning: \"" + message + "\""));
6979
}
7080

71-
@After
81+
@AfterEach
7282
public final void resetTestGlobals() {
7383
PersistedConfiguration.throwExceptions = false;
7484
PersistedConfiguration.errorReporter = DataLogManager::log;
85+
assertAll(collectedErrors);
7586
}
7687

7788
protected enum ValuesKind {
@@ -80,7 +91,7 @@ protected enum ValuesKind {
8091
}
8192

8293
private NetworkTableEntry getTableEntry(String key, NetworkTableType expectedType) {
83-
NetworkTableEntry entry = isolatedPreferences.getPreferencesTable().getEntry(key);
94+
NetworkTableEntry entry = preferencesTable.getEntry(key);
8495
assertThat(entry.getType()).isEqualTo(expectedType);
8596
return entry;
8697
}
@@ -102,8 +113,7 @@ protected final String getStringValue(String key) {
102113
}
103114

104115
protected final void setIntegerValue(String key, int value) {
105-
NetworkTable table = isolatedPreferences.getPreferencesTable();
106-
NetworkTableEntry entry = table.getEntry(key);
116+
NetworkTableEntry entry = preferencesTable.getEntry(key);
107117
entry.setInteger(value);
108118
entry.setPersistent();
109119
}
@@ -116,15 +126,16 @@ protected final void assertHasNoChangesSince(Map<String, Object> previousValues)
116126
}
117127

118128
protected final Map<String, Object> preferenceValues() {
119-
NetworkTable table = isolatedPreferences.getPreferencesTable();
120129
return preferenceKeys().stream()
121-
.collect(toMap(Function.identity(), key -> table.getEntry(key).getValue().getValue()));
130+
.collect(
131+
toMap(
132+
Function.identity(),
133+
key -> preferencesTable.getEntry(key).getValue().getValue()));
122134
}
123135

124136
protected final Set<String> preferenceKeys() {
125-
NetworkTable table = isolatedPreferences.getPreferencesTable();
126137
Set<String> keys = new HashSet<>();
127-
collectKeys(table, keys);
138+
collectKeys(preferencesTable, keys);
128139
return Set.copyOf(keys);
129140
}
130141

@@ -200,11 +211,7 @@ public void preferenceNameMapsToOnlyOneRecordType() {
200211
.containsMatch("Preference with name '" + preferenceName + "' already registered");
201212

202213
// Assert: topic added under "/PersistedConfiguration", and is not persistent
203-
NetworkTable table =
204-
isolatedPreferences
205-
.getPreferencesTable()
206-
.getInstance()
207-
.getTable(REGISTERED_CLASSES_NETWORK_TABLE_KEY);
214+
NetworkTable table = ntInstance.getTable(REGISTERED_CLASSES_NETWORK_TABLE_KEY);
208215
NetworkTableEntry entry = table.getEntry(preferenceName);
209216
assertThat(entry.exists()).isTrue();
210217
assertThat(entry.isPersistent()).isFalse();
@@ -340,20 +347,17 @@ public void withExistingPreferences_passingRecordClass() {
340347
}
341348
}
342349

343-
@RunWith(Parameterized.class)
344-
public static class BooleanPreferencesTest
350+
@Nested
351+
@ParameterizedClass(name = "defaultValue={0}")
352+
@ValueSource(booleans = {true, false})
353+
public class BooleanPreferencesTest
345354
extends PreferencesRegistryTestCase<BooleanPreferencesTest.RecordWithBooleans> {
346355
static final String PREFERENCE_NAME = "Booleans";
347356
static final String BOOLEAN_VALUE_KEY = "Booleans/booleanValue";
348357
static final String BOOLEAN_SUPPLIER_KEY = "Booleans/booleanSupplier";
349358
static final Set<String> ALL_KEYS = Set.of(BOOLEAN_VALUE_KEY, BOOLEAN_SUPPLIER_KEY);
350359
final boolean defaultValue;
351360

352-
@Parameters(name = "defaultValue={0}")
353-
public static Object[] data() {
354-
return new Object[] {true, false};
355-
}
356-
357361
public BooleanPreferencesTest(boolean defaultValue) {
358362
super(PREFERENCE_NAME, RecordWithBooleans.class);
359363
this.defaultValue = defaultValue;
@@ -429,19 +433,16 @@ protected void assertSuppliersHaveUpdatedValues(RecordWithBooleans record) {
429433
}
430434
}
431435

432-
@RunWith(Parameterized.class)
433-
public static class IntPreferencesTest
436+
@Nested
437+
@ParameterizedClass(name = "storeAsDoubles={0}")
438+
@ValueSource(booleans = {true, false})
439+
public class IntPreferencesTest
434440
extends PreferencesRegistryTestCase<IntPreferencesTest.RecordWithInts> {
435441
static final String PREFERENCE_NAME = "Integers";
436442
static final String INT_VALUE_KEY = "Integers/intValue";
437443
static final String INT_SUPPLIER_KEY = "Integers/intSupplier";
438444
final boolean storeAsDoubles;
439445

440-
@Parameters(name = "storeAsDoubles={0}")
441-
public static Object[] data() {
442-
return new Object[] {true, false};
443-
}
444-
445446
public IntPreferencesTest(boolean storeAsDoubles) {
446447
super(PREFERENCE_NAME, RecordWithInts.class);
447448
this.storeAsDoubles = storeAsDoubles;
@@ -533,7 +534,8 @@ protected void assertSuppliersHaveUpdatedValues(RecordWithInts record) {
533534
}
534535
}
535536

536-
public static class LongPreferencesTest
537+
@Nested
538+
public class LongPreferencesTest
537539
extends PreferencesRegistryTestCase<LongPreferencesTest.RecordWithLongs> {
538540
static final String PREFERENCE_NAME = "Longs";
539541
static final String LONG_VALUE_KEY = "Longs/longValue";
@@ -616,7 +618,8 @@ protected void assertSuppliersHaveUpdatedValues(RecordWithLongs record) {
616618
}
617619
}
618620

619-
public static class DoublePreferencesTest
621+
@Nested
622+
public class DoublePreferencesTest
620623
extends PreferencesRegistryTestCase<DoublePreferencesTest.RecordWithDoubles> {
621624
static final String PREFERENCE_NAME = "Doubles";
622625
static final String DOUBLE_VALUE_KEY = "Doubles/doubleValue";
@@ -699,7 +702,8 @@ protected void assertSuppliersHaveUpdatedValues(RecordWithDoubles record) {
699702
}
700703
}
701704

702-
public static class StringPreferencesTest
705+
@Nested
706+
public class StringPreferencesTest
703707
extends PreferencesRegistryTestCase<StringPreferencesTest.RecordWithStrings> {
704708
static final String PREFERENCE_NAME = "Strings";
705709
static final String STRING_VALUE_KEY = "Strings/stringValue";
@@ -781,7 +785,8 @@ protected void assertSuppliersHaveUpdatedValues(RecordWithStrings record) {
781785
}
782786
}
783787

784-
public static class RecordPreferencesTest
788+
@Nested
789+
public class RecordPreferencesTest
785790
extends PreferencesRegistryTestCase<RecordPreferencesTest.RecordWithRecords> {
786791
static final String PREFERENCE_NAME = "Records";
787792
static final String recordValueKey = "Records/recordValue";

lib/src/test/java/com/team2813/lib2813/util/InputValidationTest.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright 2023-2025 Prospect Robotics SWENext Club
2+
Copyright 2023-2026 Prospect Robotics SWENext Club
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.
@@ -19,14 +19,14 @@
1919
import static com.google.common.truth.Truth.assertWithMessage;
2020
import static org.junit.Assert.assertThrows;
2121

22-
import org.junit.Test;
23-
import org.junit.experimental.runners.Enclosed;
24-
import org.junit.runner.RunWith;
22+
import org.junit.jupiter.api.Nested;
23+
import org.junit.jupiter.api.Test;
2524

26-
@RunWith(Enclosed.class)
2725
public class InputValidationTest {
26+
2827
// Tests for the `InputValidation.checkCanId(...)` method.
29-
public static class CheckCanIdTest {
28+
@Nested
29+
public class CheckCanIdTest {
3030
@Test
3131
public void invalidCanId() {
3232
// Can IDs can only valid in the range [0, 62].

testing/build.gradle

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,10 @@ dependencies {
2626
// the magic line that makes tests work :)
2727
wpi.java.configureTestTasks(test)
2828

29-
tasks.named('test') {
30-
// Support running both JUnit Vintage and JUnit Jupiter tests
29+
test {
3130
useJUnitPlatform {
32-
excludeTags('ignore-outside-testkit')
31+
excludeTags 'ignore-outside-testkit'
3332
}
34-
systemProperty 'junit.jupiter.extensions.autodetection.enabled', 'true'
3533
}
3634

3735
publishing {

vision/build.gradle

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ dependencies {
1414
testImplementation 'com.google.truth:truth:1.4.4'
1515
testImplementation project(':testing')
1616
testRuntimeOnly('org.junit.platform:junit-platform-launcher')
17-
testRuntimeOnly('org.junit.vintage:junit-vintage-engine')
1817

1918
nativeDebug wpi.java.deps.wpilibJniDebug(wpi.platforms.desktop)
2019
nativeDebug wpi.java.vendor.jniDebug(wpi.platforms.desktop)
@@ -29,7 +28,6 @@ wpi.java.configureTestTasks(test)
2928

3029
test {
3130
useJUnitPlatform()
32-
systemProperty 'junit.jupiter.extensions.autodetection.enabled', 'true'
3331
}
3432

3533
publishing {

0 commit comments

Comments
 (0)