Rotest - An easy to use test framework (open source)


An easy to use test framework for Roblox.

You can find it on GitHub


  • Write tests using ModuleScripts with no dependancies.
  • One-file runner deployment.
  • Readable and configurable output.


It’s just one file, so you can copy the contents of src/Rotest.lua into a ModuleScript in game.ReplicatedStorage.

Or, you can also install using the package under release/rotest.rbxmx:

  • Inside Roblox Studio right-click on Workspace and click on Insert from file.
  • Browse to release/rotest.rbxmx and Open.
  • Then move Rotest/Rotest to game.ReplicatedStorage.

Running tests

  1. Start Server.
  2. Open Command Bar.
  3. Run the following command: require(game.ReplicatedStorage.Rotest):run()

Tests can be run via the command-line using run-in-roblox.

Each test will be executed in parallel using coroutines.

Writing tests

  • Tests are just ModuleScripts named to end with .test.

  • Any methods in the test will be ran in the suite. Prefix private methods with _ to prevent running.

  • If you use camelCase for the test names, they will be turned into camel case for readability in the output.

  • If you have a constructor method called new() it will be ran before each test.

  • If you have a teardown method called teardown() it will be ran after each test.


Let’s say you have a ModuleScript that exposes a single function to round a number:

ReplicatedStorage > MathUtil

local Math = {}
function Math.round(numberToRound)
    return math.floor(numberToRound + 0.5)

return Math

We can create a test for it by creating another ModuleScript called Math.test in a Test folder.

ReplicatedStorage > Tests > Math.test

local MathUtil = require(game.ReplicatedStorage:WaitForChild('MathUtil'))

local MathUtilTest = {}
function MathUtilTest:roundsNumbersUp()
	local numberToRound = 1.5

	local roundedNumber = MathUtil.round(numberToRound)

	assert(roundedNumber == 2, "Number not rounded up")

-- Other tests here...

return MathUtilTest

We can then start a Server and call the test runner using the Command Bar:


It should output something that looks like this:

========== Rotest results =============

Collected 2 tests

  Math test:

    [x] rounds numbers up (0.00 second(s))
    [x] rounds numbers down (0.00 second(s))

==== 2 passed, 0 failed in 0.01 seconds ====


The run(basepath, config) method takes 2 argument:

  • basepath - is the base path that the test runner will use to search for tests.
  • config - a table can have the following keys:
    • verbose - a boolean that specifies whether the runner should include every test in the output. Defaults to true

Run on server start

You can automatically run the tests when the server starts, by creating a ServerScript like this:

Game > ServerScriptService > RunTests

if game:GetService("RunService"):IsStudio() then


More Examples

  • Utils - Example of testing some simple util functions with no side effects.
  • Datastore - Example of a simple datastore wrapper that loads player data. Shows how to use setup and teardown.
  • Event - Example of a simple event handler. Includes a fairly sophisticated mock.

Why another unit test framework?

Who’s using it?

We are using it while developing Splash Music.


I’m kind of confused on why somebody should use this framework over one like TestEZ.

What exactly is the disadvantage of the BDD-style? In my experience it scales well and is easy to use. TestEZ also provides a lot of assertion functions which makes life easier.

Don’t get me wrong, this is a cool library, and having more options is good. I just don’t really understand the need to fit.


The main advantages is that tests are written simply as Lua modules with no dependancies (injected or otherwise), which means there’s nothing new to learn to start writing tests.

Rotest is similar in spirit to libraries like PyTest and xUnit, which utilise more language features rather than framework to write tests.

It’s all a matter of opinion, so if you’re happy using TestEz then there’s no reason to switch.

Hope that helps :heart:

1 Like