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.