Unity Community


Results 1 to 6 of 6

  1. Posts
    781

    .Net Unity Unit Test Framework - NUUnit - C#

    I've used http://nunit.org extensively for Unit Testing C# apps, however it's not compatible with Unity.

    I ran across a Unity forum post for UUnit http://forum.unity3d.com/viewtopic.p...ighlight=uunit, however it was written in BOO script.

    I adapted part of the NUnit source code to work with Unity (as a C# script) and attached an example project that shows all the same attributes work.

    A typical test class looks similar to the following.

    Code:  
    1. using System;
    2.  
    3. [TestFixture]
    4. public class MyTestClass
    5. {
    6.     [TestFixtureSetUpAttribute]
    7.     public void MyTestFixtureSetUpAttribute()
    8.     {
    9.         TestRunner.ReportLog("Call setup once before all [Test] and [SetUp]");
    10.     }
    11.  
    12.     [SetUp]
    13.     public void MySetUp()
    14.     {
    15.         TestRunner.ReportLog("Call setup before each [Test]");
    16.     }
    17.  
    18.     [Test]
    19.     public void MyGoodTest()
    20.     {
    21.         TestRunner.ReportLog("Do a good test");
    22.     }
    23.  
    24.     [Test]
    25.     public void MyBadTest()
    26.     {
    27.         TestRunner.ReportLog("Do a bad test");
    28.         throw new System.Exception("I did a bad thing");
    29.     }
    30.  
    31.     [TearDown]
    32.     public void MyTearDown()
    33.     {
    34.         TestRunner.ReportLog("Call after each [Test]");
    35.     }
    36.  
    37.     [TestFixtureTearDown]
    38.     public void MyTestFixtureTearDown()
    39.     {
    40.         TestRunner.ReportLog("Call setup once after all [Test] and [TearDown]");
    41.     }
    42. }

    To run these tests, you don't need to instantiate anything. Simply run

    Code:  
    1. TestRunner.Execute();

    Using reflection, any class that you've added [TestFixture] will be found.

    I used the same attributes that you'd be familar with if you've used Visual Studio or NUnit for unit testing.

    There's an button in the example that runs the unit tests.

    Output is written to the console output.


    If you aren't already familar with NUnit, take a look at their site and read the documentation.

    Only use [TestFixture] on public classes that have a valid constructor. I say this because you might try to use [TestFixture] on a MonoBehaviour script, so don't do that. Instead create a new test class and use a public reference to your MonoBehavior script. If you need to, you could get away with using a ScriptableObject.


    I didn't port the Asserts from NUnit.

    Code:  
    1. Assert.Fail(); Assert.AreEqual();

    Instead if a [Test] method should throw a System.Exception, the test failed. If an exception wasn't thrown it will pass.


    The test results for a run would look like the following:
    Code:  
    1. [TestRunner] **** Summary ****
    2. [PASS] MyTestClass.MyTestFixtureSetUpAttribute
    3. [PASS] MyTestClass.MySetUp
    4. [PASS] MyTestClass.MyGoodTest
    5. [PASS] MyTestClass.MyTearDown
    6. [PASS] MyTestClass.MySetUp
    7. [FAIL] MyTestClass.MyBadTest
    8. [PASS] MyTestClass.MyTearDown
    9. [PASS] MyTestClass.MyTestFixtureTearDown


    To use:

    import the package NUUnit.unitypackage


    Open:

    Tests\TheScene
    Attached Files


  2. Location
    ěresundsregionen
    Posts
    465
    Cool - thanks for sharing
    ElectroCute * Smack Boxing * TouchWars * Monster Ball * Smack Hockey * Tactical Soldier
    Unity SmartFoxServer API * Unity Asset Server Commit Mailer
    Follow on twitter: http://twitter.com/thomas_h_lund


  3. Location
    Lausanne, Switzerland
    Posts
    316
    Ah, I hate doing tests but it's so useful!

    Thanks a lot for converting it in C#. I'll sure use it in a near future (or at least if if I'm not too lazy )

  4. Keyboard operator

    Location
    Copenhagen, Denmark
    Posts
    2,929
    Bookmarked. Thanks.
    Emil "AngryAnt" Johansen

    Game developer, AI specialist, Unity expert
    Freelancer, ex Unity Technologies

    AI in Unity, tips and tricks: http://angryant.com, http://twitter.com/angryant

    Coding bare-footed grants you extra CPU cycles!


    Want to play? http://angryant.com/freelance/
    Behave 2 is out! http://angryant.com/2013/12/23/Behave-2-2/
    Check out ReView!


  5. Location
    Kansas City, MO
    Posts
    60

    Some thoughts...

    Haven't had a chance to look at this yet, but you can more or less expect a patch to show up on this thread and/or the wiki once I do.

    Thoughts:

    1) The point of actually having explicit asserts is to add clarity. With throw statements, I'm invariably going to wind up having to visually scan for throw, then expand my focus upward to find the conditional statement wrapping the throw to understand the root cause. Things get trickier if I fall into the habit of letting "hidden" (not in the actual code of the test) throws crop up and relying on those as my assert conditions. Perfectly reasonably to implement Assert using exceptions of course, but wrapping it up in some syntactic sugar and treating those assertions preferentially / differently than assertions from "deeper" in the code is going to turn the tests into actual *documentation*.

    2) Printing error messages with the failure is usually really handy.

    3) One major thing this could use is the ability for a test method to be a coroutine. Especially in light of the fact that things like Update() aren't parametric (I.E. don't receive Time.* as explicit parameters, making it harder to set up tests for them) I don't know how much effort that would be, but it could be worthwhile. On the flipside, my worry is that might introduce a tendency towards tests that over-reach and are not well scoped. I'm considering just making some base classes to facilitate this -- an abstract class such as:

    public abstract class UpdateBehaviour : MonoBehaviour {
    void Update() { OnUpdate(Time.time, Time.deltaTime, Time.frameCount); }
    public abstract void OnUpdate(float t, float dT, int frame);
    }

    In such a case you could write tests that directly called OnUpdate with explicit values, and be able to test a considerable percentage of the typical use-cases, but of course you'd be hamstrung by things like Unity lifecycle events not happening in proper order if you called OnUpdate multiple times to simulate multiple frames. For example, the code to be tested creates a GO and adds a component to it in frame 1, then expects in frame 2 that Start() has executed properly on the created object. On top of that, such a mechanism would add overhead for iPhone that might add up to be significant.

    -JF


  6. Posts
    781
    Keep in mind what I provided is unit testing in 12 lines or less.

    Of course the Asserts and GUI could be useful.

    There are tons of features in the NUnit source code for TestResults and Assert logic.

    I'm working with a slightly modified version of this package that allows me to select which tests are invoked.

    I do have tests that create game objects, run test methods, and then destroy the game object.

    Spawned game objects can Start and Update.

    If you call a game object that starts a coroutine, it could wait for the game object to awaken and update before doing your validation. You would have to put this code into a class that extends MonoBehaviour.

    Code:  
    1.    IEnumerator WaitForSecondsWrapper(float secs)
    2.     {
    3.         yield return new UnityEngine.WaitForSeconds(secs);
    4.     }
    5.  
    6. StartCoroutine(WaitForSecondsWrapper(1f));

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •