Unity DOTS Life Tutorial entities 0.4.0 preview.10 #6 ECS unit testing : Update Entities 0.8.0

Published January 15, 2020 by AntHillPlan
Do you see issues with this article? Let us know.
Advertisement

<<Previous Tutorial

This tutorial covers writing unit tests for ECS. This is a practical tutorial on the process not an essay on what to test. If you read nothing else read the IMPORT: box below on pressing apply.

Checked against 2019.3.5f1 & Entities 0.8.0 Preview.8 on March 13, 2020. Packages used are shown here

Note: DOTS Platforms is not the latest. It is only 0.2.1 preview 4 because Entities 0.8.0 does not compile with 0.2.2Burst 1.3.0 preview.6 is also not the latest. preview.5 & preview.7 can cause errors at run time depending on what Entities functions are called.

The source is at https://github.com/ryuuguu/Unity-ECS-Life.git. The Zip file of the project is at http://ryuuguu.com/unity/ECSLifeTutorials/ECSLifeTutorial6.zip

Warning: DOTS is still bleeding edge tech. Code written now will not be compatible with first release version of DOTS. There are people using the current version DOTS for release games, but they usually freeze their code to specific package and will not be able use future features without rewriting existing code first to compile and run with newer versions. So if you need 10,000 zombies active at once in your game this is probably the only way to do it. Otherwise this tutorial is a good introduction if you think you will want to simulate thousands of entities in the future or just want a get a feel for code this type of thing in Unity.

The basic steps are to put the ECS code into an Assembly definition. Make a test Assembly folder with test code and Test Assembly Definition. Run tests with Test Runner.

The code you want tested needs to be in an Assembly Definition. This means it needs to be in a folder with an Assembly Definition. For simplicity I have put all ECS related code together in "ECS Code".

I then made an Assembly Definition using the context menu in the project panel Create > Assembly Definition. I added 4 Assembly Definition References

  • Unity.Entities
  • Unity.Mathematics
  • Unity.Rendering.Hybrid
  • Unity.Burst

I found these mainly by trail and error. If you are missing any Assembly Definitions you will get a compile error. In your code editor (I am using Rider ) the using statement which calls a missing assembly will be marked ( in red in Rider ). If you call to some of your own code that is not in an assembly you will get an error that Class/Struct can not be found. This is why I included ECSGridSCDeaths.cs which is does not have any system of component code but is called from some ECS code.

IMPORTANT: After making changes to any Assembly Definition press apply inside the inspector. If you switch to another object Unity will popup a window asking you if you want to apply unapplied changes. Pressing apply here does not work properly. It looks ok and you will not get an error message but your tests may not show up and you may get compile errors.

You must make a folder for your test. In the project pane context menu use

Create > Testing > Test Assembly folder

I set the platforms to Editor only since I don't want my tests to be included in any builds.

The test specific code is these lines.

namespace Tests {
    [TestFixture]
    [Category("ECS Test")]
    public class GenerateNextStateSystemTests: ECSTestsFixture {
        [Test]
        public void WhenDeadAndNEquals3() {

var instance = m_Manager.CreateEntity();

World.CreateSystem<GenerateNextStateSystem>().Update();
Assert.AreEqual(1, m_Manager.GetComponentData<NextState>(center).value);

Using a namespace is not required but will stop name conflicts. [TestFixture] is required. [Category("ECS Test")] is not required but is recommended to help organize your tests. The class must inherit from ECSTestsFixture and the test methods must be marked with [Test] . m_Manager is a field of ECSTestsFixture and is the EntityManager used in tests. After setting up your test entities call the Update() method the system you want to tested. Use Assert to create a test result.

using NUnit.Framework;
using Unity.Entities;
using Unity.Entities.Tests;
using Unity.Mathematics;

namespace Tests {
   [TestFixture]
   //[Category("ECS Test")]
   public class GenerateNextStateSystemTests:ECSTestsFixture {
       [Test]
       public void WhenDeadAndNEquals3() {
           var _cells = new Entity[3,3];
       
           for (int x = 0; x < 3; x++) {
               for (int y = 0; y < 3; y++) {
                   var instance = m_Manager.CreateEntity();
                   m_Manager.AddComponentData(instance, new Live { value = 0});
                   m_Manager.AddComponentData(instance, new PosXY { pos = new int2(x,y)});
                   _cells[x, y] = instance;
               }
           }

           var i = 1;
           var j = 1;
           var center = _cells[i, j];
           m_Manager.SetComponentData(_cells[0,0 ], new Live { value = 1});
           m_Manager.SetComponentData(_cells[0,1 ], new Live { value = 1});
           m_Manager.SetComponentData(_cells[0,2 ], new Live { value = 1});
               
           m_Manager.AddComponentData(center, new NextState() {value = 0});
           m_Manager.AddComponentData(center, new Neighbors() {
               nw = _cells[i - 1, j - 1], n = _cells[i - 1, j], ne =  _cells[i - 1, j+1],
               w = _cells[i , j-1], e = _cells[i, j + 1],
               sw = _cells[i + 1, j - 1], s = _cells[i + 1, j], se =  _cells[i + 1, j + 1]
           });
           
           World.CreateSystem<GenerateNextStateSystem>().Update();
           Assert.AreEqual(1, m_Manager.GetComponentData<NextState>(center).value);
       }
   }
}

Finally use the Test Runner Pane to run the tests

In conclusion the process of making and running tests is pretty straight forward once you know it. The only tricky point being pressing the Apply button as note in the IMPORT: box above. I lied in the intro I will will include a couple sentences on what to test. Since ECS code is not OOP, making test that follow the strict definition of Unit tests is not possible. Systems are not methods and they work on a shared data space not on input parameters. The order that systems are run in matters and adding a new system can affect other systems in ways not possible in OOP. For example adding a tag to an entity will change its chunk and therefore change its chunk Component Data. That said I do think writing Unit Tests is good although I will also be writing some larger tests with minimal inputs. For example in Life, setup of glider and then run 4 cycles and check the results.

Cancel Save
0 Likes 0 Comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement