Using scriptable objects in unit tests

Scriptable objects are very useful to store different data. For example, I use them to store color schemes for switching between light and dark mode.

[CreateAssetMenu(fileName = "Data", menuName = "Reko/Color Scheme", order = 1)]
public class ColorScheme : ScriptableObject
{
    public Color Background;
    public Color Primary;
    ...
}

I can create a bunch of color schemes and drag and drop the one I want to use to the according component in the scene editor.

public class ColorTheme : MonoBehaviour
{
    [SerializeField]
    private ColorScheme m_darkScheme;
    [SerializeField]
    private ColorScheme m_lightScheme;
    ...
}

Of course, I need them also in my unit tests. It’s important to have the correct type, because the API depends on it.

Create a new object

Scriptable objects can be created a runtime. It’s not allowed to use the constructor, but the ScriptableObject-class has a static method CreateInstance.

var scheme = ScriptableObject.CreateInstance<ColorScheme>();
scheme.Background = Color.gray;

The object is initialized with default values. You can assign different values to the public member variables.

Load scriptable objects

It’s possible to load existing scriptable objects during a unit test.

In this solution, I just search for the name of the ScriptableObject, because I don’t have to rewrite all tests if assets are moved around. Of course, it’s also possible to directly use a full path instead.

private bool TryLoadScriptableObject<T>(string soName, out T so) where T : ScriptableObject
{
    so = null;
    string[] guids = AssetDatabase.FindAssets($"t:{typeof(T).Name} {soName }");
    if (guids.Length == 0)
        return false;

    so = AssetDatabase.LoadAssetAtPath<T>(AssetDatabase.GUIDToAssetPath(guids[0]));
    return true;
}

This only works if the unit test is executed inside the Unity editor. If the unit test should run on a device, it doesn’t have access to all assets in the editor.

Prev
Virtual reality

Virtual reality

Virtual reality completely hides the real environment