Giter Site home page Giter Site logo

deftest's Introduction

DefTest

Unit testing is a software development process in which the smallest testable parts of the code are individually and independently tested. The purpose is to verify an expected and defined behavior in one part of the code as another part of it is changed to guarantee that it still behaves as expected even after the change. Being able to catch unforeseen side effects (read: bugs) early reduces the effort and cost involved in fixing them. Unit tests can be run manually but it is more common to automate the process, typically when new code is added to a version control system such as Git. This process is also known as Continuous Integration, or CI since the local changes are integrated into a shared repository, often several times a day.

This project shows one way of running unit tests in Defold using the Telescope unit testing framework. Telescope was chosen thanks to it's simplicity and clean code. A couple of other popular unit testing frameworks are:

Usage

DefTest is provided as a Defold library project for easy integration in your own project. Add the following line to your project dependencies in game.project:

https://github.com/britzl/deftest/archive/master.zip

It is recommended to run your unit tests from its own collection, set as the bootstrap collection in game.project. Add a game object and a script to the collection and use the script to set up your tests. An example:

local deftest = require "deftest.deftest"
local some_tests = require "test.some_tests"
local other_tests = require "test.other_tests"

function init(self)
    deftest.add(some_tests)
    deftest.add(other_tests)
    deftest.run()
end

And a Lua file containing some tests:

return function()
    describe("Some tests", function()
        before(function()
            -- this function will be run before each test
        end)

        after(function()
            -- this function will be run after each test
        end)

        test("Basic arithmetic", function()
            assert(1 + 1 == 2)
        end)
    end)
end

More examples of the Telescope test syntax can be seen in telescope_syntax.lua and a full example of how to setup and run tests can be seen in the test folder.

Custom asserts

Telescope provides a system for custom asserts with the following asserts available by default:

  • assert_blank(a) - true if a is nil, or the empty string
  • assert_empty(a) - true if a is an empty table
  • assert_equal(a, b) - true if a == b
  • assert_error(f) - true if function f produces an error
  • assert_false(a) - true if a is false
  • assert_greater_than(a, b) - true if a > b
  • assert_gte(a, b) - true if a >= b
  • assert_less_than(a, b) - true if a < b
  • assert_lte(a, b) - true if a <= b
  • assert_match(a, b) - true if b is a string that matches pattern a
  • assert_nil(a) - true if a is nil
  • assert_true(a) - true if a is true
  • assert_type(a, b) - true if a is of type b
  • assert_not_blank(a) - true if a is not nil and a is not the empty string
  • assert_not_empty(a) - true if a is a table, and a is not empty
  • assert_not_equal(a, b) - true if a ~= b
  • assert_not_error(f) - true if function f does not produce an error
  • assert_not_false(a) - true if a is not false
  • assert_not_greater_than(a, b) - true if not (a > b)
  • assert_not_gte(a, b) - true if not (a >= b)
  • assert_not_less_than(a, b) - true if not (a < b)
  • assert_not_lte(a, b) - true if not (a <= b)
  • assert_not_match(a, b) - true if the string b does not match the pattern a
  • assert_not_nil(a) - true if a is not nil
  • assert_not_true(a) - true if a is not true
  • assert_not_type(a, b) - true if a is not of type b

DefTest adds these additional asserts:

  • assert_same(...) - true if all values are the same (using deep compare of values)
  • assert_unique(...) - true if all values are unique (using deep compare of values)
  • assert_equal(...) - true if all values are equal (using equality operator, ==)

Running tests from a CI system

The real power of unit tests is as we have learned when the tests can be automated and run for every change made to the code. There are many CI systems available and this project will also show how to integrate with some of the more popular CI systems out there. The main idea is to configure a physical or virtual machine so that tests can be run frequently and with predictable results every time. Once the configuration of the machine is complete a script of some kind executes the tests and depending on the outcome different actions are taken. Failed tests could perhaps trigger e-mail notifications to team members or a dashboard display to light up while successful tests could trigger a build of binaries based on the tested code.

The tests for this project can either be executed from within Defold or through the run.sh script from the command line. The script will download the latest headless version of the Defold engine and the command line build tool (bob.jar), build the project and run the tests.

Using Travis-CI

The tests in this project are run on Travis-CI. The configuration can be seen in the .travis.yml file while the bulk of the work is done in the run.sh script.

Travis-CI

For an up-to-date version of the script and steps needed to run on Travis-CI please refer to the defold-travis-ci project.

Filtering tests to run

You can specify a string pattern (using normal Lua pattern matching) that will be matched against the test names to filter which tests to run:

-- only run tests containing 'foobar'
deftest.run({ pattern = "foobar" })

Code coverage

DefTest can collect code coverage stats to measure how much of your code that is tested. Code coverage data is collected using LuaCov, specifically code from a LuaCov fork where the code has undergone some minor alterations to work well with Defold. Code coverage is not automatically collected. You can enable code coverage collection like this:

deftest.run({ coverage = { enabled = true } })

When the tests have completed a code coverage report will be generated to luacov.report.out and raw stats to luacov.stats.out. The report can be uploaded directly to a service such as codecov.io or the stats can be formatted into a report format accepted by other services such as coveralls.io.

Limitations

Unit testing in Defold works best when testing Lua modules containing pure logic. Testing script and gui_script files is more related to integration tests as it not only involves your code, but also visual components and interaction between the different game objects and the systems provided by the engine. If your scripts contains complex code that you wish to test it is recommended to move the code to a Lua module and test just that module.

deftest's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

deftest's Issues

Unable to mock `sys`

I've cloned the repo, and added the following test:

diff --git a/test/test_mock.lua b/test/test_mock.lua
index 424fdbd..12c7a0d 100644
--- a/test/test_mock.lua
+++ b/test/test_mock.lua
@@ -111,5 +111,14 @@ return function()
 			assert(m.fn1() == "foo")
 			assert(m.fn2() == "bar")
 		end)
+
+		it("should be able to mock sys", function()
+			mock.mock(sys)
+			sys.get_sys_info.returns({ language = "zu" })
+			pprint(sys.get_sys_info())
+			assert(sys.get_sys_info().language == 'zu') -- FAILS HERE
+			mock.unmock(sys)
+			assert(sys.get_sys_info().language == 'es')
+	end)
 	end)
 end

When I run .test/run.sh, the pprint call prints the following (which suggests the mock didn't do anything):

DEBUG:SCRIPT:
{ --[[0x10a34d130]]
  device_ident = "",
  user_agent = "",
  device_model = "",
  manufacturer = "",
  system_name = "Darwin",
  system_version = "21.6.0",
  api_version = "",
  device_language = "es",
  territory = "US",
  language = "es",
  gmt_offset = -420
}

And I get the following test failure:

DEBUG:SCRIPT: --- ERROR REPORT ------------------
DEBUG:SCRIPT: should be able to mock sys:
DEBUG:SCRIPT: deftest/telescope.lua:233: assertion failed!
DEBUG:SCRIPT: stack traceback:
DEBUG:SCRIPT: 	[C]: in function 'assert'
DEBUG:SCRIPT: 	deftest/telescope.lua:233: in function 'assert'
DEBUG:SCRIPT: 	test/test_mock.lua:118: in function <test/test_mock.lua:115>
DEBUG:SCRIPT: 	[C]: in function 'xpcall'
DEBUG:SCRIPT: 	deftest/telescope.lua:419: in function 'invoke_test'
DEBUG:SCRIPT: 	deftest/telescope.lua:459: in function 'run'
DEBUG:SCRIPT: 	deftest/deftest.lua:75: in function <deftest/deftest.lua:73>
DEBUG:SCRIPT: stack traceback:
DEBUG:SCRIPT: 	deftest/telescope.lua:427: in function 'invoke_test'
DEBUG:SCRIPT: 	deftest/telescope.lua:459: in function 'run'
DEBUG:SCRIPT: 	deftest/deftest.lua:75: in function <deftest/deftest.lua:73>
DEBUG:SCRIPT: Generating code coverage report
DEBUG:SCRIPT:   Skipping:	builtins/render/default.render_script
DEBUG:SCRIPT:   Processing:	deftest/deftest.lua
DEBUG:SCRIPT:   Processing:	deftest/mock/fs.lua
DEBUG:SCRIPT:   Processing:	deftest/mock/gui.lua
DEBUG:SCRIPT:   Processing:	deftest/mock/mock.lua
DEBUG:SCRIPT:   Processing:	deftest/mock/time.lua
DEBUG:SCRIPT:   Processing:	deftest/telescope.lua
DEBUG:SCRIPT:   Processing:	deftest/util/check.lua
DEBUG:SCRIPT:   Processing:	deftest/util/unload.lua
DEBUG:SCRIPT:   Skipping:	remove

  • Platform is x86_64-darwin (macOS Monterey 12.5)
  • dmengine_headless is version 1.3.4 (80b1b73)
  • bob.jar is version 1.3.4 (80b1b73)

Error in run.sh "dmengine_headless cannot execute binary file"

The tests are working when running them as "Project > Build", but not via the "run.sh".

How to reproduce:

  1. Download the repo
  2. Execute ./.test/run.sh
$ ./.test/run.sh

x86_64-linux
Downloading http://d.defold.com/archive/stable/d9e9c49ab946c058f29a8b688c862d70f30e9c43/engine/x86_64-linux/dmengine_headless
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 21.6M  100 21.6M    0     0  30.5M      0 --:--:-- --:--:-- --:--:-- 30.7M
Downloading http://d.defold.com/archive/stable/d9e9c49ab946c058f29a8b688c862d70f30e9c43/bob/bob.jar
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  135M  100  135M    0     0  36.5M      0  0:00:03  0:00:03 --:--:-- 36.5M
Running bob.jar
WARNING option 'debug' is deprecated, use options 'variant' and 'strip-executable' instead.
Working...Reading classes... 1% ...done!
Cleaning engine... ...done!
2147483647% ...done!           
Building...2023-09-28 23:15:29 INFO    Extracted 'META-INF/MANIFEST.MF' from 'jar:file:/Users/mikatuo/dev/deftest/bob.jar!/lib/luajit-share.zip' to '/var/folders/02/fj8dwp59007_d6m9cw6jy9mr0000gn/T/16444846899410792920/share/META-INF/MANIFEST.MF' 
2023-09-28 23:15:29 INFO    Extracted 'luajit/jit/bc.lua' from 'jar:file:/Users/mikatuo/dev/deftest/bob.jar!/lib/luajit-share.zip' to '/var/folders/02/fj8dwp59007_d6m9cw6jy9mr0000gn/T/16444846899410792920/share/luajit/jit/bc.lua' 
2023-09-28 23:15:29 INFO    Extracted 'luajit/jit/bcsave.lua' from 'jar:file:/Users/mikatuo/dev/deftest/bob.jar!/lib/luajit-share.zip' to '/var/folders/02/fj8dwp59007_d6m9cw6jy9mr0000gn/T/16444846899410792920/share/luajit/jit/bcsave.lua' 
2023-09-28 23:15:29 INFO    Extracted 'luajit/jit/dis_arm.lua' from 'jar:file:/Users/mikatuo/dev/deftest/bob.jar!/lib/luajit-share.zip' to '/var/folders/02/fj8dwp59007_d6m9cw6jy9mr0000gn/T/16444846899410792920/share/luajit/jit/dis_arm.lua' 
2023-09-28 23:15:29 INFO    Extracted 'luajit/jit/dis_arm64.lua' from 'jar:file:/Users/mikatuo/dev/deftest/bob.jar!/lib/luajit-share.zip' to '/var/folders/02/fj8dwp59007_d6m9cw6jy9mr0000gn/T/16444846899410792920/share/luajit/jit/dis_arm64.lua' 
2023-09-28 23:15:29 INFO    Extracted 'luajit/jit/dis_arm64be.lua' from 'jar:file:/Users/mikatuo/dev/deftest/bob.jar!/lib/luajit-share.zip' to '/var/folders/02/fj8dwp59007_d6m9cw6jy9mr0000gn/T/16444846899410792920/share/luajit/jit/dis_arm64be.lua' 
2023-09-28 23:15:29 INFO    Extracted 'luajit/jit/dis_mips.lua' from 'jar:file:/Users/mikatuo/dev/deftest/bob.jar!/lib/luajit-share.zip' to '/var/folders/02/fj8dwp59007_d6m9cw6jy9mr0000gn/T/16444846899410792920/share/luajit/jit/dis_mips.lua' 
2023-09-28 23:15:29 INFO    Extracted 'luajit/jit/dis_mips64.lua' from 'jar:file:/Users/mikatuo/dev/deftest/bob.jar!/lib/luajit-share.zip' to '/var/folders/02/fj8dwp59007_d6m9cw6jy9mr0000gn/T/16444846899410792920/share/luajit/jit/dis_mips64.lua' 
2023-09-28 23:15:29 INFO    Extracted 'luajit/jit/dis_mips64el.lua' from 'jar:file:/Users/mikatuo/dev/deftest/bob.jar!/lib/luajit-share.zip' to '/var/folders/02/fj8dwp59007_d6m9cw6jy9mr0000gn/T/16444846899410792920/share/luajit/jit/dis_mips64el.lua' 
2023-09-28 23:15:29 INFO    Extracted 'luajit/jit/dis_mipsel.lua' from 'jar:file:/Users/mikatuo/dev/deftest/bob.jar!/lib/luajit-share.zip' to '/var/folders/02/fj8dwp59007_d6m9cw6jy9mr0000gn/T/16444846899410792920/share/luajit/jit/dis_mipsel.lua' 
2023-09-28 23:15:29 INFO    Extracted 'luajit/jit/dis_ppc.lua' from 'jar:file:/Users/mikatuo/dev/deftest/bob.jar!/lib/luajit-share.zip' to '/var/folders/02/fj8dwp59007_d6m9cw6jy9mr0000gn/T/16444846899410792920/share/luajit/jit/dis_ppc.lua' 
2023-09-28 23:15:29 INFO    Extracted 'luajit/jit/dis_x64.lua' from 'jar:file:/Users/mikatuo/dev/deftest/bob.jar!/lib/luajit-share.zip' to '/var/folders/02/fj8dwp59007_d6m9cw6jy9mr0000gn/T/16444846899410792920/share/luajit/jit/dis_x64.lua' 
2023-09-28 23:15:29 INFO    Extracted 'luajit/jit/dis_x86.lua' from 'jar:file:/Users/mikatuo/dev/deftest/bob.jar!/lib/luajit-share.zip' to '/var/folders/02/fj8dwp59007_d6m9cw6jy9mr0000gn/T/16444846899410792920/share/luajit/jit/dis_x86.lua' 
2023-09-28 23:15:29 INFO    Extracted 'luajit/jit/dump.lua' from 'jar:file:/Users/mikatuo/dev/deftest/bob.jar!/lib/luajit-share.zip' to '/var/folders/02/fj8dwp59007_d6m9cw6jy9mr0000gn/T/16444846899410792920/share/luajit/jit/dump.lua' 
2023-09-28 23:15:29 INFO    Extracted 'luajit/jit/p.lua' from 'jar:file:/Users/mikatuo/dev/deftest/bob.jar!/lib/luajit-share.zip' to '/var/folders/02/fj8dwp59007_d6m9cw6jy9mr0000gn/T/16444846899410792920/share/luajit/jit/p.lua' 
2023-09-28 23:15:29 INFO    Extracted 'luajit/jit/v.lua' from 'jar:file:/Users/mikatuo/dev/deftest/bob.jar!/lib/luajit-share.zip' to '/var/folders/02/fj8dwp59007_d6m9cw6jy9mr0000gn/T/16444846899410792920/share/luajit/jit/v.lua' 
2023-09-28 23:15:29 INFO    Extracted 'luajit/jit/vmdef.lua' from 'jar:file:/Users/mikatuo/dev/deftest/bob.jar!/lib/luajit-share.zip' to '/var/folders/02/fj8dwp59007_d6m9cw6jy9mr0000gn/T/16444846899410792920/share/luajit/jit/vmdef.lua' 
2023-09-28 23:15:29 INFO    Extracted 'luajit/jit/zone.lua' from 'jar:file:/Users/mikatuo/dev/deftest/bob.jar!/lib/luajit-share.zip' to '/var/folders/02/fj8dwp59007_d6m9cw6jy9mr0000gn/T/16444846899410792920/share/luajit/jit/zone.lua' 
 2% 3% 4% 5% 6% 7% 8% 9% 10% 11% 12% 13% 14% 16% 17% 18% 19% 20% 21% 22% 23% 24% 25% 26% 27% 28% 30% 31% 32% 33% 34% 35% 36% 37% 38% 39% 40% 41% 42% 44% 45% 46% 47% 48% 49% 50% 51% 52% 53% 54% 55% 56% 58% 59% 60% 61% 62% 63% 64% 65% 66% 67% 68% 69% 70% 72% 73% 74% 75% 76% 77% 78% 79% 80% 81% 82% 83% 84% 86% 87% 88% 89% 90% 91% 92% 93% 94% 95% 96% 97% 98% ...done!
 100% ...done!
Starting dmengine_headless
./.test/run.sh: line 29: ./dmengine_headless: cannot execute binary file

Testing scripts

Hi, @britzl.

I plan to add a feature to test scripts and gui_scripts files as a part of my student summer practice. Here is the link to the fork I will work in: https://github.com/vkmelnik/deftest.

Would it be appropriate to include some kind of a small game to the test folder, as an example for integration tests?
What do you think about the idea in general?

How to run async tests?

Hi @britzl, thanks as always for your time for developing tooling around Defold.

I have a question regarding async() tests. The busted documentation mentions the usage of async() / done() (http://olivinelabs.com/busted/#async-tests)

But when using it in deftest I get this error:

attempt to call global 'async' (a nil value)

Is there a different way of calling async() / done() through your wrapper?
Cheers!

Deftest ovveride assert_equals

1)It was surprise find that deftest add some new asserts(same,unique) and ovverided equals. Plz add info about that in doc.
2)Equals should log all values, as default impl do. Without, it hard to understand what wrong.

telescope.make_assertion(
	"equal",
	function(_, ...) return telescope.assertion_message_prefix .. "all values to be equal (using the equality operator)" end,
	function(...) return check.equal(...) end
)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.