Coming from an enterprise software background I am discouraged by the lack of mocking ability when running unit tests in Unity (2022.2.4).
I tried to install Pose from NuGet but found that the Unity Editor could not recognize it after installed by Rider.
Pose seems like a testing framework that would allow for proper and powerful mocking of static methods (Physics!) in a unit test setup.
What tools do the rest of you use to conduct unit testing. Creating scenes for every little thing you want to assert seems like an huge time-sink.
Depends heavily on what you want to test. Testing built-in physics isnât going to work because it is not deterministic (DOTS physics is though). Unless you only refer to raycasting.
I only ever used tests in Unity for calculations, collections, algorithms, benchmarking, serializing and such. Never gameplay or UI and the like. I bet hardly anyone unit tests those.
1 Like
I donât want to test âgameplayâ. Letâs take a small example:
var array = Physics.OverlapSphere(requestedTargetPosition, formationRadius + FORMATION_PLACEMENT_BUFFER, LayerMask.GetMask("Unit"));
if (array.Length == 0)
{
return requestedTargetPosition;
}
I would love to mock what Physics.OverlapSphere returns (0, 1 or many item) and then assert that rest of the calculations do what they are supposed to. Without this capability I have to do the static calls in monobehaviours and pass everything in.
The reason for doing it in pure unit (component?) test is that they are very fast executing unlike play tests.
I understand there are many different approaches to testing, but within the C# world the idiomatic approach to mocking is primarily interface substitution, followed by sub-classing or similar forms of test doubles. This of course relies on the fact that the application itself is designed from the ground up with the necessary seams. In your example, you wouldnât use a static method to call into the Physics system, because that would be considered a code smell due to the tight coupling and implicit dependency. The subjectively âcleanestâ solution would be to inject an interface IPhysics via the constructor and call OverlapSphere on that. You can then mock that implementation manually or via one of the available frameworks, for example NSubstitute. To follow this line of thought I can recommend books and other content by Mark Seemann aka ploeh.
Unity however doesnât really adhere to what others in the .NET world would call good design. Itâs full of static APIs, concrete implementations and there are almost no seams to inject your own code for testing. I can only assume the big benefit of this approach is its simplicity for beginners or for quick prototyping. For enterprise-level testing, we could come up with some guidelines specific to Unity:
-
Move logic away from MonoBehaviour and donât test the imperative scripting part (things called in Start, Update, connecting Unity UI, Physics triggers, etc).
-
Insert seems for the important logic and test the plain C# classes with mocked dependencies via interface injection.
-
Use unit-testing only for important business logic (e.g. damage calculations in an RPG) and setup high-level integration tests like you mentioned via testing scenes or prefabs configured for that purpose. Yes, itâs additional maintenance, but a mocking framework doesnât magically make this go away, it just helps a little. You can achieve the same by building helper systems to make it easier to setup test content in code or similar approaches.
Other than that, not much comes to mind. Never seen Pose used in Unity. Most devs donât actually test at all and the studios that Iâve seen doing testing focus mostly on integration tests, which are indeed a pain to maintain but can eliminate lots of manual testing, so it might be worth it. The most success I actually see with content testing, e.g. prefab/scene validation. So maybe, instead of testing if the OverlapSphere logic is correctly executed, simply validate that all target prefabs have the correct layer assigned, a radius that is greater than 1 and some other condition.