I’d be grateful for some feedback on how to Test when the systems use EntityCommandBufferSystems.
This is the way I set it up:
DeathSystemTest.cs
[TestFixture]
public class DeathSystemTest : BaseTest<DeathSystem>
{
[Test]
public void setsDeadIfMaxStaminaIsEqualZeroTest()
{
var entity = em.CreateEntity(typeof(SoldierStatus));
em.SetComponentData(
entity,
new SoldierStatus
{
maxStamina = 0
}
);
World.Update();
Assert.True(em.HasComponent<Dead>(entity));
}
}
The BaseTest class:
BaseTest.cs
public class BaseTest<T> : ECSTestsFixture where T : class
{
protected EntityManager em;
public T s;
[SetUp]
public override void Setup()
{
base.Setup();
DefaultWorldInitialization.AddSystemsToRootLevelSystemGroups(World, new List<Type>());
em = m_Manager;
s = World.GetOrCreateSystem(typeof(T)) as T;
var group = World.GetOrCreateSystem<SimulationSystemGroup>();
group.AddSystemToUpdateList(s as ComponentSystemBase);
World.SetTime(new TimeData(1.234, 0.016f));
}
}
The above sets up the three basic groups, with the DeathSystem in the SimulationSystemGroup.
In short: When status.maxStamina is <= 0, the code commandBuffer.AddComponent<Dead>(entity) is run.
However, the assertion Assert.True(em.HasComponent<Dead>(entity)) fails after the World.Update(). I checked that the entity is the same as in the test.
How do I get the commandBuffer to replay before I test the assertion? I assumed that should happen automatically in the World.Update() – am I wrong?
Ah, I guess the [UpdateInGroup(typeof (SimulationSystemGroup), OrderLast = true)] in EndSimulationEntityCommandBufferSystem is not automatically adhered to?
I assumed since the line World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>() is generally used, that it would also correctly add it to the right group. (But it doesn’t since now it works)
I also use ECSTestsFixture, which is the base class of my BaseTest. How do you tick them manually, including running a playback on the commandBuffer?
If you follow the default world initialization you’ll see that everything is done in
DefaultWorldInitialization.AddSystemsToRootLevelSystemGroups
where all systems, including buffers, are added to system groups.
Simply calling GetOrCreate just gets or creates the system. It doesn’t add it to any system group.
As for how I ticks systems manually, this is what a test would somewhat look like from me
/// <summary> Tests for <see cref="DeathSystem"/>. </summary>
public class DeathSystemTests : ECSTestsFixture
{
private DeathSystem deathSystem;
private EndSimulationEntityCommandBufferSystem buffer;
[SetUp]
public override void Setup()
{
base.Setup();
this.deathSystem = this.World.GetOrCreateSystem<DeathSystem>();
this.buffer = this.World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
}
[Test]
public void setsDeadIfMaxStaminaIsEqualZeroTest()
{
var entity = this.m_Manager.CreateEntity(typeof(SoldierStatus));
this.m_Manager.SetComponentData(
entity,
new SoldierStatus
{
maxStamina = 0
}
);
this.deathSystem.Update();
Assert.False(this.m_Manager.HasComponent<Dead>(entity)); // ecb hasn't run
this.buffer.Update();
Assert.True(this.m_Manager.HasComponent<Dead>(entity));
}
}
Even if the update worked how you implemented, I prefer this way as it gives me control over what is updating in the test ensuring I’m only testing what I’m intending.
public class BaseTest<T> : ECSTestsFixture where T : class
{
protected EntityManager em;
public T s;
[SetUp]
public override void Setup()
{
base.Setup();
em = m_Manager;
var systems = new List<Type>
{
typeof(T),
typeof(EndSimulationEntityCommandBufferSystem)
};
DefaultWorldInitialization.AddSystemsToRootLevelSystemGroups(World, systems);
World.SetTime(new TimeData(1.234, 0.016f));
}
}
(for anybody reading this, AddSystemsToRootLevelSystemGroups also creates all systems passed to it, I think in violation of the method naming scene – since elsewhere, group.AddSystem does not, iirc)
I had quite some trouble locating where the EndSimulationEntityCommandBufferSystem is created or even referenced apart from example code, docs, or tests in the entities package. To be honest, I still don’t know how it exists before anybody calls GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>() – and even then, I’m wondering how it is added to the right group.
(So for testing, I do that in the above base class – I’d prefer some Entities package setup call where the default EntityCommandBufferSystem systems are created, will continue looking…)
It does work, but I also see your point, thank you for the example.
I mainly intended to use Update to get as close to the actual running code as possible, and to be able to test system order from the attributes UpdateInGroup etc. But I have a feeling I’ll end up having a fixed order of systems to have a clearer overview of the running systems, so your example will come in handy.