Skip to content

Commit f0e809f

Browse files
committed
Add tests for WPILibExtension
1 parent c527bf4 commit f0e809f

3 files changed

Lines changed: 202 additions & 0 deletions

File tree

testing/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ dependencies {
2929
nativeRelease wpi.java.vendor.jniRelease(wpi.platforms.desktop)
3030
simulationRelease wpi.sim.enableRelease()
3131

32+
testImplementation('org.junit.platform:junit-platform-testkit')
3233
testRuntimeOnly('org.junit.platform:junit-platform-launcher')
3334
}
3435

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.team2813.lib2813.testing.junit.jupiter;
2+
3+
import org.junit.jupiter.api.extension.ConditionEvaluationResult;
4+
import org.junit.jupiter.api.extension.ExecutionCondition;
5+
import org.junit.jupiter.api.extension.ExtensionContext;
6+
import org.junit.platform.testkit.engine.EngineTestKit;
7+
8+
/** JUnit Jupiter extension for ignoring tests unless they are run via {@link EngineTestKit}. */
9+
class IgnoreOutsideTestKitExtension implements ExecutionCondition {
10+
private static final String RUNNING_WITH_ENGINE_TEST_KIT = "com.team2813.runningInTestKit";
11+
12+
@Override
13+
public ConditionEvaluationResult evaluateExecutionCondition(ExtensionContext context) {
14+
if (context.getConfigurationParameter(RUNNING_WITH_ENGINE_TEST_KIT).isEmpty()) {
15+
return ConditionEvaluationResult.disabled("Test is intended to be only run via TestKit");
16+
}
17+
return ConditionEvaluationResult.enabled("Running via TestKit");
18+
}
19+
20+
/**
21+
* Gets a builder for a {@link EngineTestKit} that can execute tests that use {@code
22+
* IgnoreOutsideTestKitExtension}.
23+
*/
24+
public static EngineTestKit.Builder junitJupiterEngine() {
25+
return EngineTestKit.engine("junit-jupiter")
26+
.configurationParameter(RUNNING_WITH_ENGINE_TEST_KIT, "true");
27+
}
28+
}
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
package com.team2813.lib2813.testing.junit.jupiter;
2+
3+
import static com.google.common.truth.Truth.assertThat;
4+
import static com.google.common.truth.Truth.assertWithMessage;
5+
import static com.team2813.lib2813.testing.junit.jupiter.IgnoreOutsideTestKitExtension.junitJupiterEngine;
6+
import static org.junit.platform.engine.discovery.DiscoverySelectors.selectClass;
7+
8+
import edu.wpi.first.hal.HAL;
9+
import edu.wpi.first.wpilibj.DriverStation;
10+
import edu.wpi.first.wpilibj.RobotState;
11+
import edu.wpi.first.wpilibj.simulation.DriverStationSim;
12+
import edu.wpi.first.wpilibj2.command.Command;
13+
import edu.wpi.first.wpilibj2.command.CommandScheduler;
14+
import org.junit.jupiter.api.AfterAll;
15+
import org.junit.jupiter.api.BeforeAll;
16+
import org.junit.jupiter.api.MethodOrderer;
17+
import org.junit.jupiter.api.Order;
18+
import org.junit.jupiter.api.Test;
19+
import org.junit.jupiter.api.TestMethodOrder;
20+
import org.junit.jupiter.api.extension.ExtendWith;
21+
import org.junit.platform.testkit.engine.EngineExecutionResults;
22+
import org.junit.platform.testkit.engine.Events;
23+
24+
/** Tests for {@link WPILibExtension}. */
25+
public class WPILibExtensionTest {
26+
27+
static final Command FAKE_COMMAND = new Command() {};
28+
29+
@BeforeAll
30+
static void initializeHal() {
31+
if (!HAL.initialize(500, 0)) {
32+
throw new IllegalStateException("Could not initialize Hardware Abstraction Layer");
33+
}
34+
}
35+
36+
@ExtendWith({WPILibExtension.class, IgnoreOutsideTestKitExtension.class})
37+
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
38+
public static class SampleTest {
39+
40+
@BeforeAll
41+
public static void verifyFakeCommandNotScheduledBeforeAll() {
42+
CommandScheduler commandScheduler = CommandScheduler.getInstance();
43+
assertWithMessage("Expect all commands to have been cancelled")
44+
.that(commandScheduler.isScheduled(FAKE_COMMAND))
45+
.isFalse();
46+
}
47+
48+
@BeforeAll
49+
public static void verifyDriverStationEnabled() {
50+
assertThat(DriverStation.isEnabled()).isTrue();
51+
}
52+
53+
@Test
54+
@Order(1)
55+
public void verifyFakeCommandNotScheduledBeforeTest() {
56+
CommandScheduler commandScheduler = CommandScheduler.getInstance();
57+
assertWithMessage("Expect all commands to have been cancelled")
58+
.that(commandScheduler.isScheduled(FAKE_COMMAND))
59+
.isFalse();
60+
61+
commandScheduler.schedule(FAKE_COMMAND);
62+
assertThat(commandScheduler.isScheduled(FAKE_COMMAND));
63+
}
64+
65+
@Test
66+
@Order(2)
67+
public void verifyFakeCommandNotScheduledAfterTest(CommandTester commandTester) {
68+
CommandScheduler commandScheduler = CommandScheduler.getInstance();
69+
assertWithMessage("Expect all commands to have been cancelled")
70+
.that(commandScheduler.isScheduled(FAKE_COMMAND))
71+
.isFalse();
72+
73+
commandScheduler.schedule(FAKE_COMMAND);
74+
assertThat(commandScheduler.isScheduled(FAKE_COMMAND));
75+
}
76+
77+
@Test
78+
@Order(3)
79+
public void verifyCommandTester(CommandTester commandTester) {
80+
VerifiableCommand command = new VerifiableCommand();
81+
commandTester.runUntilComplete(command);
82+
command.verify();
83+
}
84+
85+
@AfterAll
86+
public static void verifyFakeCommandNotScheduledAfterAllTests() {
87+
CommandScheduler commandScheduler = CommandScheduler.getInstance();
88+
assertWithMessage("Expect all commands to have been cancelled")
89+
.that(commandScheduler.isScheduled(FAKE_COMMAND))
90+
.isFalse();
91+
}
92+
} // end SampleTest
93+
94+
@Test
95+
void verifyExtension() {
96+
// Arrange
97+
withDriverStationTemporarilyEnabled(
98+
() -> {
99+
// Schedule FAKE_COMMAND
100+
CommandScheduler commandScheduler = CommandScheduler.getInstance();
101+
commandScheduler.enable();
102+
commandScheduler.schedule(FAKE_COMMAND);
103+
boolean isScheduled = commandScheduler.isScheduled(FAKE_COMMAND);
104+
commandScheduler.disable();
105+
assertThat(isScheduled).isTrue();
106+
});
107+
108+
// Act
109+
EngineExecutionResults results =
110+
junitJupiterEngine().selectors(selectClass(SampleTest.class)).execute();
111+
112+
// Assert
113+
assertHasNoFailures(results);
114+
}
115+
116+
private void withDriverStationTemporarilyEnabled(Runnable runnable) {
117+
assertThat(RobotState.isDisabled()).isTrue();
118+
DriverStationSim.setEnabled(true);
119+
DriverStationSim.notifyNewData();
120+
assertThat(RobotState.isDisabled()).isFalse();
121+
122+
try {
123+
runnable.run();
124+
} finally {
125+
DriverStationSim.setEnabled(false);
126+
DriverStationSim.notifyNewData();
127+
}
128+
}
129+
130+
private void assertHasNoFailures(EngineExecutionResults results) {
131+
assertHasNoFailures(results.containerEvents());
132+
assertHasNoFailures(results.testEvents());
133+
}
134+
135+
private void assertHasNoFailures(Events events) {
136+
events.assertStatistics(
137+
stats -> {
138+
stats.skipped(0);
139+
stats.failed(0);
140+
});
141+
}
142+
143+
private static class VerifiableCommand extends Command {
144+
private static final int EXPECTED_EXECUTION_COUNT = 4;
145+
private int initializedCount = 0;
146+
private int executionCount = 0;
147+
148+
void verify() {
149+
assertWithMessage("initialize() should be called").that(initializedCount).isGreaterThan(0);
150+
assertWithMessage("initialize() should not be called more than once")
151+
.that(initializedCount)
152+
.isLessThan(2);
153+
assertWithMessage("execute() should be called until isFinished() returns false")
154+
.that(executionCount)
155+
.isEqualTo(EXPECTED_EXECUTION_COUNT);
156+
}
157+
158+
@Override
159+
public void initialize() {
160+
initializedCount++;
161+
}
162+
163+
@Override
164+
public void execute() {
165+
executionCount++;
166+
}
167+
168+
@Override
169+
public boolean isFinished() {
170+
return executionCount >= EXPECTED_EXECUTION_COUNT;
171+
}
172+
}
173+
}

0 commit comments

Comments
 (0)