Wondering if someone could help me with this. So im trying to write simple test to validate code as I go but im not sure how to go about this. how do I run jobs from my system ?
For example …
using NUnit.Framework;
namespace Universe.Planet.Tests
{
[TestFixture]
[Category("ECS Test")]
public class PlanetRuntimeTest
{
[Test]
public void CheckEntityCount()
{
// Create test world
// Initialize my system I want to test from my game
// Run job in this system
// Assert entity count
// I assume i need some sort of cleanup
}
}
}
You can also call update just that system instead of updating a world with 1 system. But there are various points I don’t like. For example if your system send some commands to ECBS then you will not see playback result unless you also add that to your test world by hand and also update it afterwards. If you use the world with 1 system approach and add ECBS systems to the world so updating the world also playback commands, they may not be the right place because the built in ECBS was fix-sorted by a special routine in the primary 3 component system groups code. Also if your system used changed filter as an update criteria / required, then you may need to manually cause dirty state so that the manual .Update call would work. (The .Update call on system still obey update conditions, it can’t force an update)
Or you can also test by viewing data combination as a unit instead of system. This way you can get the world to looks like at runtime. Create test world, add all systems like runtime, add data that you expect the system you want to test to transform them, then update world. (EcsTesting/WorldTestBase.cs at master · 5argon/EcsTesting · GitHub) Personally I only do it this way now since I could hack Time, I could see results from all ECB systems, I could test changed filter, etc. Some reviews of all approaches : https://gametorrahod.com/ecs-testing-review/
Unit testing is by far the bigger bang for buck, and at a minimum you shouldn’t be integration testing things you don’t also have unit tests for.
If you want to test what a job produces, then unit test what happens in a single Execute. IF for some reason that has side affects then you might need to test a sequence of Executes.
Be careful not to unit test ECS itself, that’s an easy mistake to make when starting to test. Sort of a cardinal rule in testing, don’t test other shit especially not third party stuff. Like say you want to test entities created in a job via ECB. You shouldn’t be testing ECB. You should be testing does your code call the ECB api’s with the right data the right number of times for the given input. To do that you can mock ECB, you could mock the job itself, etc…
There is nothing wrong with throwing in some integration level tests if you really need them, maybe ECS actually has a bug for example or you are using the api wrong and need to figure out what you are doing wrong. But that’s different then as a standard practice using integration testing while also not unit testing, which just flat out doesn’t work well. So if you want to start testing stuff as a practice then start with unit testing.
The most important thing here is keep your testing scope as limited as possible. There is nothing wrong with integration testing per say. It doesn’t really matter what label you use really. The larger lesson learned is the more isolated your tests, the more effective and less brittle they are.
When I need to test system functionality I usually just copy Unity’s testing class and test the same way they do. You derive your testing class from ECSTestsFixture and go from there. It lets you write nice and simple test, schedule jobs, query, all that. You can see how Unity does it with their systems in Packages/Entities/Unity.Entities.Tests
Im trying to validate some entity data that is created at runtime but it doesn’t make sense to me how I can access the data from a system in my tests. To make thing harder I have one system creating the entities and another setting data c. Im also brand new to NUnit so really have no idea what im doing, spend a day reading docs but it falls apart for me when it comes to ECS. I also trolled your and 5argons gits to see if i can read over an example that would do what I need , any help or doc would be appreciated
using NUnit.Framework;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[TestFixture]
public class ECSTest : ECSTestsFixture
{
[Test]
public void SomeTest()
{
var systema = World.GetOrCreateSystem<SystemA>();
var systemb = World.GetOrCreateSystem<SystemB>();
var em = EmptySystem.EntityManager;
var entity = em.CreateEntity(typeof(Whatever));
World.Update();
Assert.AreEqual(5, em.GetComponent<Whatever>(entity).value );
}
}
If you need to query for a component do you can do EmptySystem.GetEntityQuery();
Yeah, it will basically run “OnUpdate” for every system in the world. You can also force all running jobs to complete with entityManager.CompleteAllJobs(), which is useful if you need to read your input data after a system processes it.
And just a bit of advice since I’ve been there, I remember the first time I started reading about testing, all the crazy terminology and sheer volume of material on the subject made my head spin. Mocking, integration tests, In my personal experience you can ignore 99% of it.
Almost every test I write follows the exact same pattern - declare inputs, declare what you’re testing, run the test, assert. Keep it simple and readable, don’t get bogged down trying to get fancy and writing a bunch of “utility” code for testing. I’ve rarely had to write a test much longer than what I posted above - if you find yourself doing so then the thing you’re testing might be trying to do too much.
That works well for me at least, your mileage may vary of course.
I ended up trying to do something like this but out of the box it didn’t update my system. It looks like World.Update() will only update the InitializationSystemGroup, SimulationSystemGroup, and PresentationSystemGroup and those groups don’t seem to be automatically created for me. I had to manually create one of those systems and add my own system to it’s update list. Something like:
[Test]
public void SomeTest()
{
var group = World.GetOrCreateSystem<SimulationSystemGroup>();
var systema = World.GetOrCreateSystem<SystemA>();
var systemb = World.GetOrCreateSystem<SystemB>();
group.AddSystemToUpdateList(systema);
group.AddSystemToUpdateList(systemb);
var em = EmptySystem.EntityManager;
var entity = em.CreateEntity(typeof(Whatever));
World.Update();
Assert.AreEqual(5, em.GetComponent<Whatever>(entity).value );
}
You can also use DefaultWorldInitialization.AddSystemsToRootLevelSystemGroups(w, systems) then your manually created world w will get ensured having the top 3 groups plus added your systems you want to test sorted to the correct group.
Then can you use GameObjectConversionUtility and use ConvertScene? You can specify the test world on the conversion settings there as a destination world.
GameObjectConversionSettings setting = new GameObjectConversionSettings(){DestinationWorld = m_PreviousWorld};
Scene scn = new Scene(){ name = "Assets/Universe/Planet.Scenes/UniverseMain/PlanetsSubScenes.unity"}; // ??
GameObjectConversionUtility.ConvertScene(scn, setting);
I’m having trouble accessing assembly references in Unity.Entities.Tests to inherit from ECSTestFixture, but Unity.Entities is working.
Both assemblies are set as references in the inspector of my edit mode test assembly, but i’m getting a type/namespace does not exist error when trying to ad using.Unity.Entities.Tests;
iirc, there was an issue with referencing a test assembly and trying to derive from their ECSTestFixtures. What I did was a I pretty much copied the structure of their TestFixture and plugged it into my own test assembly.
I’m not sure if an assembly definition reference will work - I don’t have much experience with trying that.