May 4, 2012

Unit Testing UnityScript in Unity3D with SharpUnit

Tags: Technical, Unity

I have been programming mainly in Unity3D over the last fortnight, and thought it time to write some unit tests for my work. I found reference to a few testing frameworks online. The most promising appeared to be SharpUnit, and it is also released under a fairly relaxed license. However, I had to make a few changed to get it running, so this post details that work.

SharpUnit works like a standard unit testing framework for C# code in Unity3D (although all output goes to the console, but that is fine for me). Although my work has largely been in UnityScript (Unity3D’s JavaScript like language) and this didn’t work so well due to issues with compilation order and SharpUnit’s use of .Net custom attributes. After making the changes below, I found SharpUnit works well, and I’ll probably be using it for my unit testing.

Unity3D compiles scripts in a set order (as described here). Thus if you have C# code that references a UnityScript class there can be a problem - although the reverse is not such an issue. When testing UnityScript with SharpUnit this means that the C# Unity3D_TestRunner class can be an issue. It references the TestCase classes, which I want to write in UnityScript. To do this I put the SharpUnit code in a folder under the Plugins top-level folder (the Standard Assets folder would have also worked). This means the SharpUnit code is compiled first. Then my tests went in a new folder together with a UnityScript rewrite of Unity3D_TestRunner, as shown below. This UnityScript TestRunner script is then attached to the TestRunner GameObject (in a special testing scene) rather than the C# version as described in the SharpUnit instructions.

#pragma strict

import SharpUnit;

function Start () {
	var suite: TestSuite = new TestSuite();
	suite.AddAll(DummyTest());
	var res: TestResult = suite.Run(null);
	var reporter: Unity3D_TestReporter = new Unity3D_TestReporter();
    reporter.LogResults(res);
}

Other possible solutions to this problem would be to just write my code in C# or to change SharpUnit to load TestCase classes dynamically at runtime. Rewriting the TestRunner seemed easiest.

The other problem encountered is that SharpUnit uses the C# custom attribute [UnitTest] to identify its test methods. The equivalent in UnityScript is a script directive (see the relevant section here). Thus @UnitTest needs to be placed at the top of each test function.

After that change I could run UnityScript tests with SharpUnit. An example test is below:

#pragma strict

import SharpUnit;

class DummyTest extends TestCase {

    var dummy: String;  

    /** Setup test resources, called before each test. */
    function SetUp() {
        dummy = "lkjkjh"; 
    }

    /** Dispose of test resources, called after each test */
    function TearDown() {
        dummy = null; 
    }

    /** Sample test that passes */
    @UnitTest
    function TestDummy_Pass() {
        Assert.NotNull(dummy);
    }

    /** Sample test that fails. */
    @UnitTest
    function TestDummy_Fail() {
        Assert.Null(dummy);
    }
}