使用Junit4进行基于libgdx/ECS的游戏测试。如果一起执行,测试将失败

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

提问人:Max 提问时间:10/7/2023 最后编辑:Max 更新时间:10/16/2023 访问量:36

问:

长话短说:我正在使用 libgdx/ECS(实体-组件-系统)开发一个小游戏,现在我多次遇到我更改代码的问题,然后其他一些行为无法按预期工作(例如,单位无法再移动到目标位置)。

为了避免将来出现此类问题,我的想法是使用 junit4 创建简单的游戏测试。设置完所有内容后,我现在遇到了一个奇怪的问题,即如果我单独执行测试用例,它们就会通过。一旦我尝试将它们一起运行,它们就会失败。

在 @BeforeClass 方法中,我创建了 libgdx “world”,加载引擎并添加了测试所需的所有系统。每个@Test类都会添加测试所需的所有实体(包括 libgdx 体),并在特定的时间内运行引擎。在@After方法中,我确保删除测试添加的所有实体/实体。

@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());
}

这里有一个测试的例子(只是为了了解它的外观)

@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);
}

我还错过了什么?顺便说一句,我正在使用 @RunWith(GdxTestRunner.class)。这是能够在测试期间访问行为树文件所必需的。

我什至尝试从 @BeforeClass 方法中删除所有代码并将所有内容放在 @Before 方法中,但这会导致同样的问题。

也许通常不建议使用 junit 测试基于 ECS 的 libgdx 游戏。任何帮助都是值得赞赏的。

Java 测试 libgdx junit4 entity-component-system

评论

0赞 Abra 10/8/2023
我不认为 JUnit 适合测试 GUI。有GUI测试工具。也许这个网页会有所帮助:geeksforgeeks.org/software-testing-gui-testing-tool
0赞 Max 10/8/2023
我不是在测试 GUI。我只是通过“HeadlessApplication”运行我的应用程序,我放置在 libgdx 世界中的单元(主体)遵循它们的行为树。但似乎我错过了在两种测试方法之间重置游戏的基本信息。感谢您的评论。
1赞 knittl 10/8/2023
展示具体代码总是比以抽象方式描述代码更好。展示您的代码,这样人们就不必猜测它的外观。
0赞 Max 10/8/2023
我添加了代码片段。我希望这有助于更好地理解这个问题。最后,最大的问题是如何为使用 libgdx 作为引擎的实体组件系统编写 junit 测试。
0赞 Community 10/9/2023
请澄清您的具体问题或提供其他详细信息,以准确说明您的需求。正如目前所写的那样,很难确切地说出你在问什么。

答:

0赞 Max 10/16/2023 #1

我在设置中发现了问题。实际上,我有两个问题在相互执行多个测试时对行为有影响。

  1. 我试图在测试后删除基于“SteerableComponent”的实体(出于清理原因),但是当实体在测试期间死亡时,该组件已被删除。

  2. 更新引擎时,请务必避免使用以下代码,因为两个测试用例之间的增量时间大于通常的增量时间,这可能会导致问题。engine.update(Gdx.graphics.getDeltaTime());