Emulate Players for automated tests

Introduction

This guide’s aim is to show different approaches to emulating players for automated tests, and let you choose which one you want to use.

Emulating one or more players may be useful when testing logic regarding players. Some examples may be when testing .touched events that fire functions tied to players, user input, UI or the functionalities of a tool.

Method 0

The common way is to go to the Test tab, select the number of players and run a local server.

Method 1

Method 0 is great, but what if we want to run some automated tests written with TestService? That’s where TestService itself comes in handy!
Put your tests in a script, and follow the steps in the next section.

Setup

  1. Parent the script containing the code that needs the player to be emulated to TestService.
    This can be done in two ways:

    • A:
      1. If not already set, go to FILEStudio Settings → check Show hidden objects in Explorer
      2. Move the script under TestService
    • B: In command line: {YourScript}.Parent = game:GetService("TestService")
  2. Set the property ExecuteWithStudioRun of TestService to true, and we can do it via command line
    (game:GetService("TestService").ExecuteWithStudioRun = true) or clicking on TestService and checking the box ExecuteWithStudioRun.

  3. Set the number of players we want to emulate modifying the TestService’s property NumberOfPlayers, with the same process of the previous step (It’s a good idea to keep this number between 1 and 8, more would be heavy on your machine)

  4. Set the TestService’s property Timeout to a high number, for example 120, just in case it takes too long to load all the windows

  5. Run the game. Once the game is ran [2 + NumberOfPlayers] windows (one is the one in which we ran the game, one for the server, and one for each Player) of Roblox Studio will open

Extra tips:

  • All the players created will be named Player in a progressive order, so their names will be Player1, Player2 …
  • A good way to retrieve all the players could be
local players = {}
for playerIndex = 1, TestService.NumberOfPlayers do
table.insert(players, game:GetService("Players"):WaitForChild("Player"..playerIndex))
end

Pros and cons

Pros:

  • Keep tests separated from everything else
  • Enable and disable tests easily (ExecuteWithStudioRun)
  • Modify the number of players easily (NumberOfPlayers)
  • Simulate lag! (SimulateSecondsLag)

Cons:

  • More time consuming than going to the test tab and creating a local server
  • If instead of being written for TestService the tests are written for TestEZ, some benefits disappear (lag simulation, enable / disable tests easily)
  • Poorly documented API, so if any question arises it’s difficult to figure it out by yourself
  • With the TestEZ framework more complex tests can be written

Method 2

I already mentioned the TestEZ framework, but how can we do something similiar with it?
We can combine this method and method 0 to get the wished result, making it way faster than method 1.
To get the player we then do:

game:GetService("Players"):WaitForChild("Player1", 30)

Pros and cons

Pros:

  • Fastest route
  • Tests can be more complex and there are more resources about this API around the internet

Cons:

  • Tests deactivation / activation is not as quick as method 1 (unless you have a script that only requires and runs the tests, in which case the speed is the same)
  • Can’t keep them separated from everything else (putting the script in TestService will result in the tests not running)

Conclusion

Method 1 has everything in one place and is easy to enable and disable, method 2 has better capabilities and is quicker to set up.
The choice of which one you want to use is yours, even though my favourite method is method 2

If you have anything to add, correct, or have a different method of emulating a player via script, please let me know! :+1:

Resources

4 Likes

So this is a manual server start of the automated one in the TEST tab?

You haven’t made clear what code we should put in the script.

Yes, even though it’s a longer route the advantage of this method is that it can be combined with TestService to run automated tests, keeping them separate from the other scripts. It will be easy to enable and disable those tests (if you add new features and want to test everything again to make sure it still works), since the only step is to set TestService’s ExecuteWithStudioRun to true or false.

In the script you put your tests. For example, I recently had to test the functioning of a checkpoint system, and I had to move a player around the map. To do so I used this method, and once done with the tests I simply set TestService’s ExecuteWithStudioRun to false.

I’m updating my post with the reason why this method might be more beneficial instead of the classic way.
Thanks for the input!

1 Like