javatestinglibgdxjunit4entity-component-system

Using Junit4 for game tests based on libgdx/ECS. Tests failing if executed together


Long story short: I am developing a small game with libgdx/ECS (Entity-Component-System) and had now mutiple times the issue that I changed the code and afterwards some other behavior was not working like expected (e.g. units were not able anymore to move to target position).

To avoid such issues in the future my idea was to create simple game tests with junit4. After setting up everything I have now the strange issue that the test cases are passing if I execute them separately. As soon as I try to run them together they are failing.

In the @BeforeClass method I create the libgdx "world" load the engine and add all required systems for the tests. Each @Test class adds all the entities (including libgdx bodies) required for the test and runs the engine for a specific amount of time. In the @After method I make sure that I delete all entities/bodies that the test has added.

@BeforeClass // executed once before all tests are performed 
public static void setupWorld() {

    world = new World(new Vector2(0, 0), true);
    //create a pooled engine
    engine = new PooledEngine();
    
    testUtility = new TestUtility(engine, world);

    // init factories
    bodyFactory = BodyFactory.getInstance(world);
    unitFactory = UnitFactory.getInstance(bodyFactory, engine);
    battleMap = new BattleMap(sceneryFactory, engine, 123, 0); // create a battle map without any terrain or scenery

    // add all the relevant systems our engine should run
    engine.addSystem(new FormationSystem());
    engine.addSystem(new PhysicsSystem(world));
    engine.addSystem(new FollowPathSystem(battleMap));
    engine.addSystem(new FollowFlowFieldSystem()); // this system works only for units!
    engine.addSystem(new ArriveSystem());
    engine.addSystem(new TurnTowardsSystem(engine));
    engine.addSystem(new FightSystem(engine, world));}

@After
public void cleanUp() throws Exception {
    // destroy all bodies in the world
    testUtility.destroyObsoleteStaticBodies();
    testUtility.destroyObsoleteDynamicBodies();
    // remove all steerable entities
    engine.removeAllEntities(Family.all(SteerableComponent.class).get());
    // remove all entities that contain the static body components
    engine.removeAllEntities(Family.all(BodyComponent.class).get());
    engine.clearPools();
    // check if world is reset correctly
    assertEquals("Number of bodies in the world should be zero.", 0, world.getBodyCount());
    assertEquals("Number of fixtures in the world should be zero.", 0, world.getFixtureCount());
}

Here an example of the test (just to get an idea how it looks like)

@Test
public void checkIfUnitTurnTowardsAttackingEnemy() {
    placeUnits(new Vector2(5,5), new Vector2(5,6));
    testUtility.runEngine(5, false);
    // get the steerable of the enemy unit to check if it has turned around
    SteerableComponent steerComp = engine.getEntitiesFor(Family.all(Enemy_Tag.class).get()).get(0).getComponent(SteerableComponent.class);
    float orientationAngle = MathHelper.simplifyAngle((float)Math.toDegrees(steerComp.body.getAngle()));
    assertTrue("Enemy unit that got attacked should have turned around. Offset in degrees: " + (orientationAngle-180), orientationAngle <= 180 + SteerableComponent.ANGLE_REACHED_THRESHOLD 
                                                                               && orientationAngle >= 180 - SteerableComponent.ANGLE_REACHED_THRESHOLD);
    assertTrue("Enemy should have angular velocity of zero.", steerComp.body.getAngularVelocity() <= SteerableComponent.ZERO_ANGULAR_SPEED_THRESHOLD);
}

What else am I missing? Btw I am using the @RunWith(GdxTestRunner.class). This is required to be able to access behavior tree files during the tests.

I have even tried to remove all code from the @BeforeClass method and put everything in the @Before method but this leads to the same problem.

Maybe testing libgdx games based on ECS is in general not recommended with junit. Any help is appreciated.


Solution

  • I have found the issue in my setup. Actually I had two issues that had an impact on the behavior when performing mulitple test after each other.

    1. I tried to delete entities after the test (for clean up reasons) based on the "SteerableComponent" but this component was already removed when an entity died during the test.

    2. When updating the engine it is important to avoid the below code because the delta time between two test cases is bigger than the usual delta time which can lead to issues. engine.update(Gdx.graphics.getDeltaTime());