Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Docs] Create a document describing ways to test an Entitas Redux project using Unity Test Runner #46

Open
jeffcampbellmakesgames opened this issue Jan 11, 2021 · 4 comments
Labels
documentation Improvements or additions to documentation

Comments

@jeffcampbellmakesgames
Copy link
Owner

How to test your project using the Unity Test Runner (currently with NUnit) | no need to do it like this anymore https://www.youtube.com/watch?v=DZpvUnj2dGI

@jeffcampbellmakesgames jeffcampbellmakesgames created this issue from a note in Documentation (To do) Jan 11, 2021
@jeffcampbellmakesgames jeffcampbellmakesgames added the documentation Improvements or additions to documentation label Jan 11, 2021
@matthiashermsen
Copy link

@jeffcampbellmakesgames I would like to work on this.

Since I'm not an expert on this I would like to provide the wiki content here as a comment so you can review it first

@jeffcampbellmakesgames
Copy link
Owner Author

@jeffcampbellmakesgames I would like to work on this.

Since I'm not an expert on this I would like to provide the wiki content here as a comment so you can review it first

That sounds good; I can also help to supply content for this based on some of the knowledge gained from unit testing the framework itself and different approaches used there.

@jeffcampbellmakesgames jeffcampbellmakesgames moved this from To do to In progress in Documentation Jan 12, 2021
@matthiashermsen
Copy link

matthiashermsen commented Jan 13, 2021

@jeffcampbellmakesgames this is a first prototype. For the assembly definition part I'm not sure what needs to be added so for now I just added everything. I would put this wiki page to the getting started section.

Please take care for the move system test example, this is not done yet :D

Setting up tests

Requirements

Entitas-Redux and Genesis are installed and Genesis is configured.

Unity test framework

You can find more about it here.

Setting up the tests environment

First you need to create a tests assembly folder. This can be done via the Asset folder context menu

Create => Testing => Tests Assembly Folder

After creating it you should see the following warning in the editor console

Assembly for Assembly Definition File 'Assets/Tests/Tests.asmdef' will not be compiled, because it has no scripts associated with it.

Unity needs to know the location of your code, the tests assembly definition needs a reference to the assembly definition of your code. At the root of your code directory create a new assembly definition

Create => Assembly Definition

Now head over to the tests assembly definition and add your code assembly definition to the list. After that, don't forget to save your changes by clicking on apply at the bottom.

image

Now Unity knows about your code. Head over to the code assembly definition and add Entitas-Redux and Genesis as a reference to that assembly definition. Do the same for the tests assembly definition. Otherwise the tests environment doesn't know about external packages like Entitas-Redux or Genesis. After that, don't forget to save your changes by clicking on apply at the bottom.

image

Writing tests

Make sure all tests live in the tests assembly folder. Create a new test script template with

Create => Testing => C# Test Script

Running the tests

You can run the tests with the Test Runner which can be found at

Window => General => Test Runner

Test examples

The following shows some examples for different scenarios. It should give a rough overview about testing in its simplest form.

Testing an init system creating a grid of x * y entities with unique field indices

Given the example components and init system

[Game, Unique]
public sealed class BoardSizeComponent : IComponent
{
    public Vector2Int value;
}

[Game]
public sealed class FieldIndexComponent : IComponent
{
    [PrimaryEntityIndex]
    public Vector2Int value;
}

public sealed class FieldConstructionSystem : IInitializeSystem
{
    private readonly Contexts _contexts;

    public FieldConstructionSystem(Contexts contexts)
    {
        _contexts = contexts;
    }

    public void Initialize()
    {
        Vector2Int boardSize = _contexts.Game.BoardSize.value;
        
        for (int x = 0; x < boardSize.x; x++)
        {
            for (int y = 0; y < boardSize.y; y++)
            {
                Vector2Int newFieldIndex = new Vector2Int(x, y);
                
                GameEntity newField = _contexts.Game.CreateEntity();
                newField.AddFieldIndex(newFieldIndex);
            }
        }
    }
}

You can test the FieldConstructionSystem by creating a FieldConstructionSystemTests script. Things you might want to test:

  • It should create an amount of entities equal to the board size
  • Each field index exists only once

The first test runs multiple times with different mock data but you can run the second test with different data too. You can even use the TestCaseSource attribute to make your test data reusable.

public sealed class FieldConstructionSystemTests
{
    private Contexts _contexts;
    private Systems _systems;

    [SetUp]
    public void Setup()
    {
        _contexts = new Contexts();
        _systems = new Systems();
        
        FieldConstructionSystem fieldConstructionSystem = new FieldConstructionSystem(_contexts);
        _systems.Add(fieldConstructionSystem);
    }
    
    [TestCase(0, 0)]
    [TestCase(100, 100)]
    [TestCase(8, 53)]
    [TestCase(27, 4)]
    [TestCase(10, 10)]
    [TestCase(71, 3)]
    [TestCase(39, 8)]
    public void ItCreatesFieldIndexEntitiesBasedOnBoardSize(int horizontalBoardSize, int verticalBoardSize)
    {
        Vector2Int boardSize = new Vector2Int(horizontalBoardSize, verticalBoardSize);
        
        _contexts.Game.ReplaceBoardSize(boardSize);
        
        _systems.Initialize();
        
        int expectedEntityAmount = boardSize.x * boardSize.y;
        int actualEntityAmount = _contexts.Game
            .GetGroup(GameMatcher.FieldIndex)
            .AsEnumerable()
            .Count();

        Assert.AreEqual(expectedEntityAmount, actualEntityAmount);
    }
    
    [Test]
    public void EachAreaIndexExists()
    {
        Vector2Int boardSize = new Vector2Int(10, 10);
        
        _contexts.Game.ReplaceBoardSize(boardSize);
        
        _systems.Initialize();
        
        for (int x = 0; x < boardSize.x; x++)
        {
            for (int y = 0; y < boardSize.y; y++)
            {
                Vector2Int currentFieldIndex = new Vector2Int(x, y);
                GameEntity fieldEntity = _contexts.Game.GetEntityWithFieldIndex(currentFieldIndex);
                
                Assert.NotNull(fieldEntity);
            }
        }
    }
}

Testing an update system moving an entity horizontally by one once per frame

Given the example component and update system


!!!

@jeffcampbellmakesgames since #43 is not done yet I have to check how to refactor and improve this system x)

!!!


[Game]
public sealed class PositionComponent : IComponent
{
    public Vector2Int value;
}

public sealed class MoveSystem : IUpdateSystem
{
    public void Update()
    {
        IEnumerable<GameEntity> entities = Contexts.SharedInstance.Game
            .GetGroup(GameMatcher.Position)
            .AsEnumerable();

        foreach (GameEntity entity in entities)
        {
            Vector2Int oldPosition = entity.Position.value;
            Vector2Int newPosition = new Vector2Int(oldPosition.x + 1, oldPosition.y);
            
            entity.ReplacePosition(newPosition);
        }
    }
}

You can test the MoveSystem by creating a MoveSystemTests script. You want to test that the horizontal position increases incrementally by 1 once per frame.

Unfortunately the TestCase attribute is not supported, but you can use ValueSource instead. You can find more information here.

For the sake of simplicity this test only runs once


!!!

@jeffcampbellmakesgames the test is not passing yet x) Have to check how to write Unity tests

!!!


public sealed class MoveSystemTests
{
    private Contexts _contexts;
    private Systems _systems;

    [SetUp]
    public void Setup()
    {
        _contexts = new Contexts();
        _systems = new Systems();
        
        MoveSystem moveSystem = new MoveSystem();
        _systems.Add(moveSystem);
    }

    [UnityTest]
    public IEnumerator TheEntityMovesHorizontallyOncePerFrame()
    {
        Vector2Int initialEntityPosition = new Vector2Int(8, 53);
        
        GameEntity entity = _contexts.Game.CreateEntity();
        entity.AddPosition(initialEntityPosition);
        
        _systems.Update();
        
        yield return null;
    
        int expectedHorizontalTargetPosition = initialEntityPosition.x + 1;
        
        Assert.AreEqual(expectedHorizontalTargetPosition, entity.Position.value.x);
    }
}

@matthiashermsen
Copy link

@jeffcampbellmakesgames I'm not sure if my suggestions are still up to date but for now I would like to unassign myself and wait for a review :)

@matthiashermsen matthiashermsen removed their assignment May 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
Documentation
  
In progress
Development

No branches or pull requests

2 participants