Junit tests hanging in Github Action, but not when run in VSCode

We have been adding Unit tests to our robot software, mostly following the examples in WPILIB and the unit testing docs. Everything was fine, but today we added a test for checking a command, and it spins up an entire robot in simulation. When we run the test in VSCode as part of the build, it works perfectly. However, we also use Githib Actions to run a build whenever we push code to our main branch, and with the new test the action times out. We see the output from the new test as passed, and even from older tests that run after it, but when the whole test task should end and the action should move on to the next task, it just hangs until the timeout.

I added some code at the end of the “AfterEach” section to dump all of the threads running, and in addition to the Junit threads, it showed the robot threads still running, such as “robot main”, “thread 0”, “DataLogDS”, “NTListener”, and “MotorSafety”. My thought is that the action is waiting for these threads to exit, but that is just a guess. Is there something else that we should be doing at the end to quite out of it? The AfterEach already does a robot.endCompetition, robot.close, an interrupt call on the competition thread as well as all the other things in the example. Any ideas as to what I am missing?

If you want to take a look at it, the repo is at GitHub - ToughTechs151/robot-template: Template for Tough Techs robots.

By the way, the example unit tests in WPILIB show calls to HAL.initialize, but it looks to me like the WPILIB code does that already. Is the call really necessary?

Yes, your unit test code must call HAL.initialize() before calling any HAL simulation functions. The WPILib code that calls HAL.initialize() is only called in the top level RobotBase class. You should be writing unit tests that do not instantiate the entire robot, but rather specific pieces of testable code, as RobotBase (e.g. TimedRobot) is not designed to ever exit.

Okay, but we were following the code in wpilibjExamples/src/test/java/edu/wpi/first/wpilibj/examples/armsimulation/ArmSimulationTest.java

Does it have a different purpose than we thought?

That test is designed to be an integration/system test.
For more specific unit testing, see the UnitTest example and the accompanying frc-docs page: Unit Testing — FIRST Robotics Competition documentation

Given that we shouldn’t spin up a whole robot for unit testing, and the recommended way to create command now is to use composition and lambdas, etc., what would be the recommended way to test those commands? Is there a simulated scheduler or a way to use the scheduler without the rest of the robot?

Sure, you can just instantiate a unique instance of CommandScheduler in a test, eg allwpilib/wpilibNewCommands/src/test/java/edu/wpi/first/wpilibj2/command/NotifierCommandTest.java at main · wpilibsuite/allwpilib · GitHub

Um, no you can’t - that ctor is package-private, and spinning up a separate instance causes a lot of shortcuts to not work.

You can use the singleton instance as usual, just clear it before/after each test.

When it comes to closing stuff in WPILib, there’s definitely room for improvement – feel free to open issues/PRs.