11

I'm writing a game over libgdx; I'm using the junit framework to simplify unit-testing my code. Now there's part of the code (a map generator, a class converting my own map format into TiledMap...) which I need to test thoroughly, but it uses libgdx code: from file handling to asset loading. I'm not planning to test the actual graphical output, or the game itself, in this way: but I want to test the single components (calculation, asset access...) to avoid blatant errors.

I've tried to do something like this in the "setUpBeforeClass" method:

    LwjglApplicationConfiguration cfg = new LwjglApplicationConfiguration();
    cfg.useGL20 = true;
    cfg.width = 480;
    cfg.height = 320;
    cfg.resizable = true;
    LwjglApplication app = new LwjglApplication( new TestApplicationListener(), cfg);

And calling within tearDownAfterClass():

    Gfx.app.exit()

But it does create a window I do not need, and seems overkill when all I need is the file handling initialized. Is there a better way to initialize the libGDX components without creating an entire application object? Thanks.

EDIT

Going back over it (thanks to Sam in the comments), I realize GL access is needed (loading assets requires it), but this approach does not seem to work: the graphic library does not seem to be initialized. GDX documentation hasn't helped. Any clue?

Community
  • 1
  • 1
Calimar41
  • 222
  • 2
  • 11
  • Using the approach you outlined, I'm able to use the file handling but not any of the graphics module - presumably since it all runs the separate rendering thread. I realise that you weren't aiming to test graphics, but have you come across a way to make calls to the graphics module in a unit test? Any help much appreciated! – Cabbage soup Apr 10 '14 at 19:28
  • Yep the approach above works, but does in fact create an empty main window. I would assume you can perform the whole game operations since that's the case: I'll add a test for one of the screens and check it out. – Calimar41 Apr 11 '14 at 09:52
  • In fact, my tests fail when accessing anything from Gdx.gl - apparently, the above is not sufficient to initialize the GL part. I'm investigating further - part of my testing involves texture loading, so I'll need it too! – Calimar41 Apr 11 '14 at 10:02
  • Why not use mocks then? Take your pick: mockito + powermock, jmockit, easy mock, etc. You'd be easily simulating the libgdx behaviour as needed in your testcase, allowing you to verify how your components behave. – Morfic Apr 11 '14 at 10:50
  • Part of my problem comes from the fact libgdx javadoc is lacking; I'm not sure if I'm using the right method (example: I was trying to extract regions from a TextureAtlas via getTextures(), which broke my code). Mocks - with which I have little to no experience with - seem to assume I know what the actual method should return; if that's the case, I'd be testing my code against unverified assumptions. If this makes sense. Correct me if I'm wrong. – Calimar41 Apr 11 '14 at 11:10
  • I'm using EasyMock, but I'm finding it very difficult to simulate the Gdx.gl behaviour. – Cabbage soup Apr 11 '14 at 11:21
  • My other approach was to try to get access to the rendering thread, using the [postRunnable()](http://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/backends/lwjgl/LwjglApplication.html#postRunnable(java.lang.Runnable)) method on the LwjglApplication I used to set up the test environment, but that seems to only let you push jobs to the main thread, not the rendering thread. – Cabbage soup Apr 11 '14 at 11:23

2 Answers2

13

This question hasn't been answered and I am surprised nobody has pointed out the headless backend, which is ideal for this situation. Combine this with your favorite mocking library and you should be good to go.

public class HeadlessLauncher {
    public static void main(final String[] args) {
        final HeadlessApplicationConfiguration config = new HeadlessApplicationConfiguration();
        config.renderInterval = Globals.TICK_RATE; // Likely want 1f/60 for 60 fps
        new HeadlessApplication(new MyApplication(), config);
    }
}
Jyro117
  • 4,519
  • 24
  • 29
  • 1
    To combine this with JUnit tests, you can use `GdxTestRunner` from https://github.com/TomGrill/gdx-testing. – Thomas Jun 21 '16 at 13:29
3

As already showed there is a HeadlessApplication backend which gives you an initialized libGDX but has no OpenGL context. For working with OpenGL you indeed need the LwjglApplication backend which creates an OpenGL window.

If you have problems writing tests which rely on the OpenGL context keep in mind that OpenGL is only attached to the thread of your LwjglApplication which is not the tread of your tests. Your tests have to call Gdx.app.postRunnable(Runnable r) to access the thread with the OpenGl context.

You may want to use synchronized and CountDownLatch to pause the test while waiting for your application to execute the command.

Sebastian
  • 5,721
  • 3
  • 43
  • 69
  • I am trying to do this exact thing, but am unable to communicate back to junit (I'm pretty new to java). It seems that CountDownLatch is a way to keep the Gdx.app and junit threads synchronized - is there any way to detect pass/fail in the Runnable code? Ie, junit `assert`s in the Gdx.app thread will not affect the junit thread, so the junit thread needs to detect what has happened in the Runnable code. Do you know of a way to do that? – SheerSt Sep 10 '15 at 03:16
  • I wanted to tell you that this would qualify as a new question rather than a comment, but than I saw that meanwhile you already have asked and have been helped :-) If anyone stubles about this comment, see: http://stackoverflow.com/questions/32492526/libgdx-junit-testing-how-do-i-communicate-with-the-application-thread – Sebastian Sep 12 '15 at 19:07