Search Unity

Question Any proper mocking frameworks for Unity unit testing?

Discussion in 'Testing & Automation' started by unity_VsH8UFcNnoltTw, Nov 26, 2022.

  1. unity_VsH8UFcNnoltTw

    unity_VsH8UFcNnoltTw

    Joined:
    Aug 28, 2021
    Posts:
    2
    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.
     
  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    6,005
    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.
     
  3. unity_VsH8UFcNnoltTw

    unity_VsH8UFcNnoltTw

    Joined:
    Aug 28, 2021
    Posts:
    2
    I don't want to test 'gameplay'. Let's take a small example:

    Code (CSharp):
    1.   var array = Physics.OverlapSphere(requestedTargetPosition, formationRadius + FORMATION_PLACEMENT_BUFFER, LayerMask.GetMask("Unit"));
    2.  
    3.             if (array.Length == 0)
    4.             {
    5.                 return requestedTargetPosition;
    6.             }
    7.  
    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.
     
  4. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,188
    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.