Unit Testing

So just finished watching this video on how Rare uses Test-Driven Development to make sure Sea of Thieves doesn’t have any funky bugs that will creep up on them later on in development.

This got me thinking about how could someone do this using Phaser 3.

At the moment, the way I’ve figured it out is that I would have to create a fake DOM (e.g. using jsdom) and then run the tests after the game has preloaded assets. I’d have to create the DOM either each time, or destroy the game world and create the new scene to test things in.

I honestly don’t know, apart from trying a few tutorials, I have never really used unit test libraries before, but if anyone has done this before or has a good idea of how to achieve it, please leave your comment below.

Also, there’s this thread on html5gamedevs that kinda gives clues on what to do.

You could always use something like chromatic or applitools.

In my opinion, I think you should consider this approach:

Use Phaser minimally. All the actual game logic runs in a webWorker, and Phaser is literally only used to display things.

That way, ideally, you don’t even need Phaser to play your game and a text-only version is possible.

Caveats: this probably works best for ‘slow’ games like turn-based JRPGs or turn-based strategy games.

What you’re describing is not unit testing. If you have to emulate a browser you’re more likely describing integration tests. Unit tests focus on testing individual, well, units. That should include only single pieces of functionality, ideally only single functions. You’ll want to architect your code so that logic is decoupled from rendering in order to make it easily testable.

@ldd makes an interesting point about utilizing web workers. This would force you to decouple your logic, albeit at the expense of introducing complexity into your codebase.

Also remember to not test things that Phaser itself should be responsible for testing. For example, you don’t need to test that after your preload function, create is called.

My advice would be to not try and learn how to test while also trying to make a game. If you find along the way that you’ve created a particularly complex piece, isolate and test just that (after attempting to simplify to eliminate the need to test). And keep in mind that 100% coverage is unattainable. You’ll pull your hair out first.

1 Like

Whatever you do, listen to @jorbascrumps . Do not attempt 100% coverage.

If I were in your position, I’d just isolate whatever code I can unit test, and well, test it (using jest, etc).

The thing to look for is long functions (with more than, say, 30 lines of code or nested if statements). Try to extract that code into smaller functions that you can unit test.

That way, your create/update methods are relatively clean
e.g:

// file1: probable a scene class
create(){
 this.thingies = longProcessToinitializeMySprites(this.add)
 anotherLongProcess(this.add, this.thingies)
}

update(){
 if (hasOnlyCoolSprites(this.thingies)){
   coolProcess(this.thingies, this.input)
 }
}

and then you can unit test hasOnlyCoolSprites, coolProcess, etc because if you really think about it, they may not really depend too much on an actual game running.

Mind you, this approach does introduce some unnecessary abstraction and sacrifices readability of your code, but we are just talking about possible approaches, so just take this as generic ideas and not things you have to do.

1 Like

This isn’t to test just UI, it’s to test logic (e.g. collisions, AI, player movement, etc.). Of course things like audio will be near impossible to test, but when it comes to the logic. Unit tests can be made. The question, of course, is how?

Also, I have been thinking about using a web worker to do all the logic for a while now, but would rather do tests on that first. I’m quite worried about memory being an issue especially on mobiles. But anyways, that isn’t what this thread was about :laughing:.

Unit tests can be used for faster paced games, it’s just writing the unit tests themselves is the struggle. If these guys at Rare can do it with something as vast and complex as Unreal engine, then we can as well.

OK, let me start by clarifying things first, and I think I’ll update the question to fit this mold as well: I’m curious as to how one would implement unit and integration tests using Phaser in a NodeJS environment.You then run the tests in this fake environment.

I am OK with Phaser running the render function, actually I think it would be good, since if there’s an issue with my code or the version of Phaser during rendering I can catch the issue. I know you stated that I shouldn’t test what Phaser should be testing, but I feel like this will also save me time, since i won’t have to spend hours trying to fix a bug that is caused by the framework I’m using.

@ldd did make a good point, but I think most people responding haven’t realized that I plan on using NodeJS to test (probably because I haven’t mentioned it). I can’t remember, but I do not think workers are stable in NodeJS yet. I remember them being experimental (I checked, they still are).

“100% coverage is attainable” said every programmer before trying to attain 100% coverage and failing. But yes, thank you though I’ll definitely keep this in mind, also I’ll try to find a way to train myself in the use of some of these testing tools.

OK, now I’m even more curious, should the I use jest then. Because I have been thinking of using it. Also, is there a difference in tooling for unit tests and integration tests? (@jorbascrumps). What tools, in relation to game development, would be good for testing.

So code wise, yes your code would be in a Scene class, but imagine a Scene for each test we want to run. So i’m guessing it would be unit tests first and then that would follow up with Integration tests.

Yes.

usually people choose jest for unit/integration, cypress/testcafe/nightwatch/etc for end to end.

Even if you’re working on a server side web application the separation should be :

  • View/Controller Layer

    • requests
    • sessions
    • api serializer instantiation → see service layer
    • form body validation → see service layer
    • responses
  • Service Layer

    • models: deals in DTOs
    • db: touches Databases
    • apiClients: makes external http requests

We can still treat phaser is the same since a Scene is just a View/Controller. It is however more like React/Angular in that you can have many views/controllers running at the same time.

2 Likes