https://github.com/jonasjurczok/faketorio
Run automatic tests for your mod inside Factorio
https://github.com/jonasjurczok/faketorio
factorio game modding modding-tools testing
Last synced: about 1 year ago
JSON representation
Run automatic tests for your mod inside Factorio
- Host: GitHub
- URL: https://github.com/jonasjurczok/faketorio
- Owner: JonasJurczok
- License: mit
- Created: 2017-09-28T19:25:05.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2019-05-09T16:50:33.000Z (about 7 years ago)
- Last Synced: 2025-03-18T18:05:57.960Z (about 1 year ago)
- Topics: factorio, game, modding, modding-tools, testing
- Language: Lua
- Homepage:
- Size: 856 KB
- Stars: 21
- Watchers: 5
- Forks: 4
- Open Issues: 22
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Faketorio

[](https://travis-ci.org/JonasJurczok/faketorio)
[](https://luarocks.org/modules/jasonmiles/faketorio)
[](https://coveralls.io/github/JonasJurczok/faketorio)
[](https://opensource.org/licenses/MIT)
Support library for automated testing of Factorio mods
## Purpose
The problem with modding in Factorio (or any other script language based modding environment) is testing.
Usually this is solved by a huge amount of manual testing. This amount grows with every new feature and every bugfix.. because in theory you have to test EVERYTHING EVERY.SINGLE.TIME (super annoying).
This is where automated testing comes in. I'm new to lua testing, but there are [a couple](http://lua-users.org/wiki/UnitTesting) unit testing frameworks available.
The problem with unit testing is that it only gets you so far. The most interesting aspect (how does it behave in the real game) is hard to mimic.
Enter Faketorio. The goal is to provide a standard system for running your mod against your local Factorio installation, execute tests INSIDE
Factorio and then package your mod for release.
## Installation
If you use [LuaRocks](https://luarocks.org) for your lua modules it is as easy as running `luarocks install faketorio`.
If you do all the dependency management yourself you will have to download the files from this github repo and place them in a convenient location. Then `require` them with the proper path.
## Usage
For a (very) short info on how to interact with faketorio type `faketorio -h`. For the long version keep reading :)
There are two main aspects of faketorio regarding your mod. The first is mod management and packaging and the second is testing.
### Mod management
With Faketorio you can run and build your mod. To do this we need two things: a `.faketorio` config file in your home folder and a certain folder
structure in your mod.
#### Folder structure
Faketorio assumes the following structure for your mod files:
```
- MyModFolder/
- info.json // the file with all your mod info
- src/ // all your mod source files go here (in as many subfolders as you like)
- control.lua
- data.lua
- settings.lua
- mymod.lua
- locale/ // all your locale files as described in [aubergine10's guide to localization](https://github.com/aubergine10/Style/wiki/Localisation)
- spec/ // all your test files go here (as described by [busted](https://olivinelabs.com/busted/#defining-tests)
- mod_spec.lua // normal [busted](https://github.com/Olivine-Labs/busted) unit tests (or any other tests for that matter)
- mod_feature.lua // faketorio tests that are run inside of Factorio
- target/ // temporary folder that faketorio uses to assemble files and folders
```
The Factorio specific files (`control.lua`, `data.lua`, `settings.lua`, ...) all go into the source folder without any additional subfolders.
#### .faketorio config file
Faketorio requires a config file to run. You can specify the location with the `-c` option. If no config path
is provided faketorio will search for a file named `.faketorio` in the current folder.
This file has to have three values configured.
```properties
factorio_mod_path = "/home/jjurczok/.factorio/mods"
factorio_run_path = "/home/jjurczok/.local/share/Steam/steamapps/common/Factorio/bin/x64/factorio"
# windows based example
factorio_run_path = "D:\Spiele\Factorio\bin\x64\factorio.exe"
faketorio_path = "/usr/share/lua/5.2/faketorio"
```
`factorio_mod_path` describes the folder where all your mods are. On my machine this is in the home folder, on windows it will be somewhere else
`factorio_run_path` is the path to the executable (Factorio.exe on windows)
`faketorio_path` is the path where you installed faketorio itself. If you installed it via `luarocks` you can find this path with `luarocks show faketorio` or `luarocks doc faketorio`
#### Including custom files
If you want to inlcude custom files into your zip you can specifiy it your `.faketorio` file like this:
```properties
include_files = {
["filename"] = "target file name"
}
```
This will look for `filename` relative to the current folder.
If the file is found it will be copied to `target/target file name`.
#### Faketorio commands
With the configuration in place and the mod structured we can now start interacting with faketorio. Faketorio should be run from your mod folder.
To do this open a terminal (or command line with start -> execute -> cmd on windows) and navigate to the folder where you do your development (ideally NOT inside the Factorio mods folder ;).
Now you can execute the faketorio commands to interact with your mod and Factorio.
Command name
Description
faketorio build
Creates a subfolder in target/<your mod name_version>.
The mod name and version are read from the info.json.
Copies all mod src files, locales and other resources to this folder.
Intended if you want to take a look at your mod but not produce an uploadable zip file.
faketorio clean
Deletes the target folder.
faketorio copy
Copies the mod to the factorio mod folder defined in the .faketorio config.
In Factorio you can click restart to see the current version of your mod.
Restarting Factorio is only necessary if you changed locales or graphics.
faketorio package
Creates a zip file that is ready for uploading to the factorio mod portal.
faketorio run
Runs the build and copy command.
Generates a new Factorio map.
Factorio is started and this newly generated map is loaded.
faketorio test
This command runs Factorio on a new map.
Your mod will also contain all your feature files and the faketorio test engine.
Ingame type /faketorio in the debug console to run all your tests.
### Tests
Now that we covered how to interact with Factorio itself it is time to talk about the real reason for this library. The actual testing.
The tests are inspired by [busted](https://github.com/Olivine-Labs/busted) and use roughly the same basic principles.
```lua
-- in mod_feature.lua
feature("My first feature", function()
before_scenario(function()
-- will be called before every scenario in this feature
-- this is intended for setting up preconditions for this specific feature
end)
after_scenario(function()
-- will be called after every scenario in this feature
-- this is intended to bring the mod back into a state as it would be expected from the next test
end)
scenario("The first scenario", function()
faketorio.click("todo_maximize_button")
faketorio.log.info("my first test")
end)
scenario("The second scenario", function()
faketorio.log.info("Scenario 2")
end)
end)
```
As described in `Folder Structure` you can create feature files in your `spec` folder. These files have to follow the naming pattern
`_feature.lua`. It is best practice to have one feature per file.
In the scenarios you can basically write normal lua code to interact with your mod. Faketorio provides you with some additional
functions that you can use.
#### Running tests ingame
To run your tests inside of Factorio simply invoke `faketorio test` in a terminal in the mod folder.
Faketorio will generate a new map, copy your mod and the tests and starts Factorio.
As soon as you are in game you can open the [debug console](https://wiki.factorio.com/Console) and enter
`/faketorio`. Simply run the command and all your tests will be executed.
You will see a dialog popping up in the middle of the screen. The top bar indicates progress on feature level,
the lower bar indicates progress on scenario level for the currently running feature.
If there are test errors they will be documented in the textbox below the progress bar after the testrun finishes.
#### Marking tests as success/failure
By default any scenario function that completes is counted as successful.
If you want to mark your test as a failure (because some assertion did not work) you can just raise an [error](https://www.lua.org/pil/8.3.html)
```lua
-- in mod_feature.lua
feature("My first feature", function()
scenario("The first scenario", function()
faketorio.print("This test is successful.")
end)
scenario("The second scenario", function()
faketorio.print("This test fails.")
error("test failure")
end)
end)
```
At the end of every test run you will receive a report to the console (and the logfile) indicating what worked and what did not.
As usual a testrun is only successful if ALL tests pass!
TODO: provide screenshots of success and failure cases
```
TESTRUN FINISHED: SUCCESS
Run contained 1 features.
```
#### Interacting with Factorio
Faketorio provides the following functions
Function name
Parameters
Return value/Action
faketorio.click
name - the name of the gui element to click on
If the element exists a defines.events.on_gui_click event for the provided element will be raised.
If the element does not exist an exception is thrown.
Currently only left clicks without modifiers (ctrl, alt, shift) are supported.
player - (optional) the player who owns the element.
If not provided the first player in game will be used
faketorio.enter_text
name - the name of the element to enter text in
Sets the text attribute of the named element to the text.
This does NOT fire all the keystroke events you would expect from actually entering the text!
text - the text to enter
player - (optional) the player who owns the element.
If not provided the first player in game will be used
faketorio.find_element_by_id
name - the name of the element
Returns the element with the given name.
Returns nil if the element does not exist.
player - The player who owns the element.
If not provided the first player in game will be used
faketorio.check
name - the name of the checkbox
Sets the checkbox state to true
If the checkbox does not exist or is not a checkbox an exception is thrown.
player - The player who owns the element.
If not provided the first player in game will be used
faketorio.uncheck
name - the name of the checkbox
Sets the checkbox state to false
If the checkbox does not exist or is not a checkbox an exception is thrown.
player - The player who owns the element.
If not provided the first player in game will be used
#### Assertions
The following assertions are provided by faketorio
Function name
Parameters
Return value/Action
faketorio.assert_element_exists
name - the name of the element
Returns the element with the given name.
Throws exception if the element does not exist.
player - The player who owns the element.
If not provided the first player in game will be used
faketorio.assert_element_not_exists
name - the name of the element
Asserts that the element does not exist.
If the element is found an exception is thrown.
player - The player who owns the element.
If not provided the first player in game will be used
faketorio.assert_checked
name - the name of the checkbox
Asserts that the checkbox is checked.
If the element is not found or is not a checkbox an exception is thrown.
player - The player who owns the element.
If not provided the first player in game will be used
faketorio.assert_unchecked
name - the name of the checkbox
Asserts that the checkbox is unchecked.
If the element is not found or is not a checkbox an exception is thrown.
player - The player who owns the element.
If not provided the first player in game will be used
#### logging
The log system functions are intended for debug output and if you want to report something to the user
while the tests are running.
The system knows four different log levels. `TRACE`, `DEBUG`, `INFO` and `WARN`. The default log level is `INFO`.
All messages that are logged with a level lower (read left in the list) as the current log level will be ignored.
Messages passed to the logging system will be printed to every player in Factorio. Additionally it will be written to the `faketorio.log` file
in your Factorio `script-output` folder in your [application directory](https://wiki.factorio.com/Application_directory).
To create log messages use one of the following functions
```lua
-- simple logging
faketorio.log.trace("my test trace message")
faketorio.log.debug("my test debug message")
faketorio.log.info("my test info message")
faketorio.log.warn("my test warn message")
-- logging with parameter expansion (prints "my test pattern wololo.")
faketorio.log.trace("my test pattern %s.", {"wololo"})
faketorio.log.debug("my test pattern %s.", {"wololo"})
faketorio.log.info("my test pattern %s.", {"wololo"})
faketorio.log.warn("my test pattern %s.", {"wololo"})
-- to change the current log level and thus limiting the output during your tests use
faketorio.log.setTrace()
faketorio.log.setDebug()
faketorio.log.setInfo()
faketorio.log.setWarn()
```
#### mocks
Sometimes it is necessary to change the behavior of your mod, pretending certain external events happened.
One example would be the user modified the mod settings. As the `settings` table is read only for the mod we can just mock
the result.
Assuming you have a function like this
```lua
function myMod.is_setting_enabled(player)
return settings.get_player_settings(player)["my-mod-setting"].value
end
```
we can now change the behavior of that function by mocking it:
```lua
local player = ...
myMod.is_setting_enabled(player) -- returns true (default value)
-- lets create a mock
when(myMod, "is_setting_enabled"):then_return(false)
myMod.is_setting_enabled(player) -- returns false (the mocked value)
myMod.is_setting_enabled:revert()
myMod.is_setting_enabled(player) -- returns true again (it calls the original function)
```
## Credits
Faketorio is inspired by [Factorio stdlib](https://github.com/Afforess/Factorio-Stdlib) and the work Afforess did there to enhance the testing.
Over time I hope to become as complete as this testing system.