UsUnit
UsUnit is an UnrealScript Unit Testing Framework, much like [JUnit] and [DUnit] being developed by El Muerte.
Unit testing makes it easier to validate correct behavior of the program during development. Tests can be seperated from the base code and can easily be rerun in order to validate if the changes made didn't break functionality.
Unit testing might seem like a lot of work, but there's a huge gain in the end.
The UsUnit Testing Framework is released under the LesserOpenUnrealModLicense, this means you can use it without limitations (even for commercial products).
Note: never include the UsUnit package and related tests with your game\mod. It should not belong in there, so make sure you don't create dependencies on UsUnit in your base code.
Usage
All UsUnit classes use the same external configuration file: UsUnit.ini
TestRunner
This is the main class that will run all given test cases and suites. There are a few ways to execute the TestRunner.
- ServerActor
- Simply add
UsUnit.TestRunner
to the ServerActors list and start a server. The tests will be started depending on the fDelayedStart value of the TestRunner. - WebAdmin
- Upon installation of UsUnit via the ut4mod the webadmin module will automatically be registered. All you have to do is to enable the webadmin, start a server and visit the WebAdmin page.
- Mutator
- A mutator is included that can also start the test runner. The mutator name is
UsUnit.UsUnitMutator
. The mutator is current in the beta stage. You can start the test runner and view some results. But that is pretty much it.
Configuration
By default TestRunner doesn't do much. You will have to define which tests to run. This can be done directly in the main configuration file UsUnit.ini
or via the WebAdmin.
[UsUnit.TestRunner] Tests=MyTests.CASE_StartupTest Tests=MyTests.SUITE_Algorithms fDelayedStart=0
- Tests
- this is a dynamic string array containing the fully qualified names of the test cases and suites to execute. They will be executed in that order. By default this list is empty.
- fDelayedStart
- this defines the number of seconds to wait before automatically starting the tests. When it's set to 0 it will start the tests as soon as the TestRunner has been spawned. If the value is negative it will not start the tests automatically, it will wait until the run command is explicitly called. fDelayedStart is only used when it's started as a ServerActor.
TestReporter
The TestReporter is resposible for reporting the test progress and results. The TestReporter can have multiple output modules. The following come standard with the UsUnit package:
Output_HTML
- This will produce a HTML file in the UserLogs directory containing the results of the tests.
Configuration
[UsUnit.TestReporter] bGenerateLogErrors=true OutputClasses=UsUnit.Output_HTML
- bGenerateLogErrors
- This will generate "error" log entries in the main log file. These can be parsed by a program to find the exact location of the check that failed. For this to work best you should use UCPP and the correct macros (that come with the UsUnit package).
- OutputClasses
- A dynamic string list containing all output modules to use.
Creating a test case
A test case extends the actor TestCase. This class will contain the code that performs the actual tests can checks. A normal test run will be like this:
- TestCase.setUp()
- TestCase.run()
- perform tests
- call done()
- TestCase.tearDown()
Note: test cases are spawned only once and never destroyed (not until a level restart). If your tests needs to initialize some data before the test is actually executed implement the setUp function, do not use any of the BeginPlay events.
The most important thing you need to do for a test case is implement the run() function. After you performed all tests in this test case you should call the function done(), if you do not do this the test cycle will never be completed.
Properties
- TestName
- a human readable name for the test
- TestDescription
- a short description of the test
Events
- run()
- will be called to run the test. You need to implement this.
- setUp()
- will be called right before run() is called, but outside the timed section. Use it to initialize data.
- tearDown()
- will be called after the test case was completed, but outside the timed section. Use it to clean up data.
Functions
- Check(bool expression, coerce string message)
- the actual check if a given condition results in true. If the condition given by expression is false this check failed. message contains a description of the current test.
- Done()
- this function must be called after all checks have been performed, otherwise the test cycle will not continue.
UCPP Notice
UsUnit comes with a macro file (UsUnit/macros.inc) that can be used with UCPP. This will add some extra magic to the Check functions. The following macros are defined:
- CHECK(expr,msg)
- this behaves much like the normal Check function, except that it will append the current filename and line where this function was called. This can be useful to find the check that failed.
- CHECK(expr)
- this will be translated to CHECK(expr,"expr"). In other words, the expression content will be converted to the description. This makes it easier in some cases like: CHECK(1+1 == 2).
To use the macro file simply add the following line before you call any CHECK:
#pragma ucpp include ../../UsUnit/macros.inc
Note: make sure you read the UCPP instructions on how to use it.
Example Test Case
More examples can be found in the UsUnitExamples package.
#pragma ucpp notice - precompile this unit with UCPP #pragma ucpp version // include the CHECK() macros to add filenames and location #pragma ucpp include ../../UsUnit/macros.inc class TEST_SimpleTests extends TestCase; function run() { local array<string> dummy; CHECK(1+1 == 2); CHECK("CaseInsensitive" ~= "caseinsensitive"); CHECK(false, "false; will always fail"); CHECK(split("one two three four five", " ", dummy) == 5, "\"one two three four five\" has 5 words"); CHECK(split("one", " ", dummy) == 1, "\"one\" is 1 word"); CHECK(round(1.5) == 2); CHECK(int(1.5) == 1); done(); } defaultproperties { TestName="Simple Tests" TestDescription="Example test case, performs some simple tests basic math testing." }
Creating a Test Suite
A test suite is nothing more than a collection of test cases and\or test suites to be executed sequentially. A test suite extends the class TestSuite. It usually doesn't contain any code, just values in the defaultproperties section.
The following class properties are of interest:
- TestName
- the name of the suite
- TestDescription
- a short description of the test suite (optional)
- TestClasses
- a dynamic array with class references to test cases and test suites that are part of this suite.
- bBreakOnFail
- if set to true it will it will not continue with the next test class when the current class failed a single check. Default: true
Example Test Suite
class SUITE_ExampleSuite extends TestSuite; defaultproperties { TestName="Example Test Suite" TestDescription="Bundles all example tests from the UsUnitExamples package" TestClasses[0]=class'TEST_SimpleTests' TestClasses[1]=class'TEST_TimedTest' }
Downloads
Development releases
Not really releases but just the lastest updates of the UsUnit packages straight from the CVS
CVS Access
- Anonymous access
- :pserver:anonymous@el-muerte.student.utwente.nl:/usr/local/cvsroot/UT2004
- Module names
- UsUnit
UsUnitExamples
Additional Information
- /ChangeLog – changes for the various releases
- /Discussion