Charlie
Charlie

Reputation: 705

UnityEngine.Object instances have no name property in test

Assigning names to my objects (like the ones returned from the global Instantiate method) is breaking my tests. Anyone have any ideas for how to get around such things in test?

using System;
using NUnit.Framework;
using UnityEngine;

[TestFixture()]
public class BoardSpec{
    [Test()]
    public void NamePropertyWorks(){
        var obj = new UnityEngine.Object();
        obj.name = "object name";
    }
}

The error I'm receiving: System.MissingMethodException : Cannot find the requested method. The first line of the stack trace gives: at (wrapper managed-to-native) UnityEngine.Object:set_name (string)

Unity 5.2.0f3, running tests in MonoDevelop-Unity 4.0.1 on osx

_____update 9/20______ It sounds like creating new Objects is not recommended, but this code fails with the same error:

    [Test()]
    public void ScriptableObjectNamePropertyWorks(){
        var obj = new ScriptableObject();
        obj.name = "object name";
    }

Upvotes: 0

Views: 846

Answers (1)

Emilio Martinez
Emilio Martinez

Reputation: 1072

Short answer: Never create nor inherit directly form UnityEngine.Object, use ScriptableObject instead

Doing something like (new UnityEngine.Object()).name = "text" will always throw a null reference exception, as I'll explain below. From there to the System.MissingMethodException you are getting, it depends on the inner workings of NUnit.

Unity uses UnityEngine.Object in a very special way, keeping track of objects, and considering some "not alive" despite existing. The Equals comparison for UnityEngine.Object is overriden to reflect this, and an existing Object might equal null:

    // Both Mesh and MyObject inherit directly from UnityEngine.Object
    Object plainObject = new UnityEngine.Object();
    Mesh meshObject = new UnityEngine.Mesh();
    MyNumber myNumber = new MyNumber(123456f);

    // using the overriden Unity.Object.Equals()
    print(plainObject != null); // false
    print(meshObject != null); // true
    print(myNumber != null); // false

    // With traditional null checking, everything exists of course, as we just created them
    print(plainObject as System.Object != null); // true
    print(meshObject as System.Object != null); // true
    print(myNumber as System.Object != null); // true

    print(myNumber.number); // prints 123456, the object is there and perfectly operational
    print(myNumber.name); // the program ends with a null reference exception thrown by the name set accessor, because myNumber is not "alive"

Every native Unity class that inherits from UnityEngine.Object makes any needed internal call to register the object as "alive", but this is not done in the base class itself. Basically, any attempt to create a vanilla Object, or something directly inherited from it, will be considered stillborn by the engine, and you won't get it to work as usual. If you need to create or inherit from Objects, use ScriptableObject instead, that has an explicitly special behaviour in the inner workings.

Upvotes: 1

Related Questions