Search Unity

Resolved Mock RaycastHit2D

Discussion in 'Testing & Automation' started by sztobar, Dec 28, 2020.

  1. sztobar

    sztobar

    Joined:
    Apr 8, 2020
    Posts:
    3
    I'm trying to cover my code with tests, especially code that deals with raycasts and raycasts hits as I constantly face issues with small miscalculations. It's really tiresome to create gameObjects and colliders, set them in specific positions, layers, sizes, and call `Physics2D.Raycast()` everytime I need to test If my code is correctly handling `RaycastHit2D` structs.

    For some reason, when `RaycastHit2D` is created manually (using new `RaycastHit2D()`) I cannot set a collider property on it.

    I've tried to use reflection to set this property using code I found on stackOverflow

    I've looked at decompiled source code of Unity here, but unfortunately the `m_Collider` type is `int32` not `Collider2D` (I'm using Unity ver. `2019.4.17f1`).

    Then I looked at UntiyCsReference and I found that inside `RaycastHit2D`, `m_Collider` is defined as an integer which seems to be instanceID of the collider.
    I've tried to set `m_Collider` on `RaycastHit2D` to `instanceID` of Collider2D but when I run the code `hit.collider` is still returning null. I also checked that after I set private field using Reflection from linked stack-overflow response, I get 0 when I use the same code to get private field value.


    1. Are there any reasons why developer cannot set `collider` property during creation of this `RaycastHit2D`?
    2. Is there any way I could mock `RaycastHit2D` using reflection or any other means?

    Solved

    As it turned out I was passing copy of `RaycastHit2D` to the function that was responsible for setting a private field, and returning unchanged original struct. That's why `m_Collider` was always set to 0. After changing the code to this:
    Code (CSharp):
    1.  
    2.     public static RaycastHit2D MockHit(Collider2D collider, Vector2 point, Vector2 normal, float distance) {
    3.       RaycastHit2D hit = new RaycastHit2D() {
    4.         point = point,
    5.         normal = normal,
    6.         distance = distance
    7.       };
    8.       object obj = hit;
    9.       Type type = obj.GetType();
    10.       FieldInfo fieldInfo = type.GetField("m_Collider", BindingFlags.NonPublic | BindingFlags.Instance);
    11.       fieldInfo.SetValue(obj, collider.GetInstanceID());
    12.       return (RaycastHit2D)obj;
    13.     }
    14.  
    15.  
    I return `obj` casted to RaycastHit2D which make it work. Previously I was returning `hit` unaware that `obj` is a copy.
     
    Last edited: Dec 28, 2020
    AlexVillalba likes this.