Update library structure to split off Testing utilities from the Utility area

This commit is contained in:
2026-06-05 22:28:13 -04:00
parent 360657a2e9
commit b80346f3b4
15 changed files with 58 additions and 10 deletions
+4 -3
View File
@@ -3,15 +3,16 @@
"rootNamespace": "BracerLib.Tests",
"references": [
"UnityEngine.TestRunner",
"BracerLib"
"BracerLib",
"BracerLib.Utility.Testing"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [
"nunit.framework.dll",
"Moq.dll"
"Moq.dll",
"nunit.framework.dll"
],
"autoReferenced": true,
"defineConstraints": [
@@ -1,12 +0,0 @@
using UnityEngine;
using UnityEngine.TestTools;
namespace BracerLib.Tests
{
[ExecuteInEditMode]
[ExcludeFromCoverage]
public class MonoBehaviourTester : MonoBehaviour, IMonoBehaviourTest
{
public virtual bool IsTestFinished { get; set; }
}
}
@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: 7e2baafc97e51834e89c53aaa65ddd67
@@ -1,5 +1,6 @@
using System;
using System.Collections;
using BracerLib.Utility.Testing;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
@@ -1,4 +1,5 @@
using System.Collections;
using BracerLib.Utility.Testing;
using Moq;
using NUnit.Framework;
using UnityEngine;
@@ -1,5 +1,6 @@
using System;
using System.Collections;
using BracerLib.Utility.Testing;
using UnityEngine;
using UnityEngine.Assertions;
using UnityEngine.TestTools;
@@ -1,4 +1,5 @@
using System.Collections;
using BracerLib.Utility.Testing;
using UnityEngine.Assertions;
using UnityEngine.SceneManagement;
using UnityEngine.TestTools;
-413
View File
@@ -1,413 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using Moq;
using NUnit.Framework;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.TestTools;
using Object = UnityEngine.Object;
namespace BracerLib.Tests
{
[ExcludeFromCodeCoverage, ExcludeFromCoverage]
public class TestBase
{
// private readonly IDictionary<Object, SerializedObject> globalPropertyCache;
private readonly IDictionary<Object, SerializedObject> objectPropertyCache;
private readonly Queue<Object> destroyOnTestEnd;
private readonly Stack<Scene> closeOnTestEnd;
private readonly Queue<IDisposable> disposeOnTestEnd;
private readonly Queue<Object> destroyOnOneTimeEnd;
private readonly Stack<Scene> closeOnOneTimeEnd;
private readonly Queue<IDisposable> disposeOnOneTimeEnd;
[ExcludeFromCoverage]
protected TestBase()
{
// globalPropertyCache = new Dictionary<Object, SerializedObject>();
objectPropertyCache = new Dictionary<Object, SerializedObject>();
destroyOnTestEnd = new Queue<Object>();
closeOnTestEnd = new Stack<Scene>();
disposeOnTestEnd = new Queue<IDisposable>();
destroyOnOneTimeEnd = new Queue<Object>();
closeOnOneTimeEnd = new Stack<Scene>();
disposeOnOneTimeEnd = new Queue<IDisposable>();
}
/// <summary>
/// Called as part of NUnit framework. Override <see cref="OneTimeSetUp"/> instead.
/// </summary>
[OneTimeSetUp, ExcludeFromCoverage]
public void DoOneTimeSetUp()
{
OneTimeSetUp();
}
[UnityOneTimeSetUp, ExcludeFromCoverage]
public IEnumerator DoUnityOneTimeSetUp()
{
yield return UnityOneTimeSetUp();
}
/// <summary>
/// Called as part of NUnit framework. Override <see cref="SetUp"/> instead.
/// </summary>
[SetUp, ExcludeFromCoverage]
public void DoSetUp()
{
SetUp();
}
[UnitySetUp, ExcludeFromCoverage]
public IEnumerator DoUnitySetUp()
{
yield return UnitySetUp();
}
/// <summary>
/// Called as part of NUnit framework. Override <see cref="TearDown"/> instead.
/// </summary>
[TearDown, ExcludeFromCoverage]
public void DoTearDown()
{
TearDown();
objectPropertyCache.Clear();
}
[UnityTearDown, ExcludeFromCoverage]
public IEnumerator DoUnityTearDown()
{
yield return UnityTearDown();
Reset();
while (closeOnTestEnd.Count > 0)
yield return CloseLatestScene();
}
/// <summary>
/// Called as part of NUnit framework. Override <see cref="OneTimeTearDown"/> instead.
/// </summary>
[OneTimeTearDown, ExcludeFromCoverage]
public void DoOneTimeTearDown()
{
OneTimeTearDown();
}
[UnityOneTimeTearDown, ExcludeFromCoverage]
public IEnumerator DoUnityOneTimeTearDown()
{
yield return UnityOneTimeTearDown();
CleanupUnityObjects(destroyOnOneTimeEnd);
CleanupDisposableObjects(disposeOnOneTimeEnd);
while (closeOnOneTimeEnd.Count > 0)
yield return CloseLatestScene(true);
}
/// <summary>
/// Pass a Unity object that will be destroyed at the end of the test.
/// </summary>
protected T RegisterTempTestObject<T>(T obj) where T : Object
{
destroyOnTestEnd.Enqueue(obj);
return obj;
}
/// <summary>
/// Pass a function that generates or returns a Unity object that will be destroyed at the end of the test.
/// </summary>
protected T RegisterTempTestObject<T>(Func<T> generator) where T : Object
{
var obj = generator();
return RegisterTempTestObject(obj);
}
/// <summary>
/// Pass a Unity object that will be destroyed at the end of all the tests in a given suite.
/// </summary>
protected T RegisterOneTimeTestObject<T>(T obj) where T : Object
{
destroyOnOneTimeEnd.Enqueue(obj);
return obj;
}
/// <summary>
/// Pass a function that generates or returns a Unity object that will be destroyed at the end of all the tests in a given suite.
/// </summary>
protected T RegisterOneTimeTestObject<T>(Func<T> generator) where T : Object
{
var obj = generator();
return RegisterOneTimeTestObject(obj);
}
/// <summary>
/// Pass a disposable object that will be cleaned up at the end of the test.
/// </summary>
protected T RegisterDisposableTempTestObject<T>(T obj) where T : IDisposable
{
disposeOnTestEnd.Enqueue(obj);
return obj;
}
/// <summary>
/// Pass a function that generates or returns a disposable object that will be cleaned up at the end of the test.
/// </summary>
/// <param name="generator"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
protected T RegisterDisposableTempTestObject<T>(Func<T> generator) where T : IDisposable
{
var obj = generator();
return RegisterDisposableTempTestObject(obj);
}
/// <summary>
/// Pass a disposable object that will be cleaned up at the end of the test.
/// </summary>
protected T RegisterDisposableOneTimeTestObject<T>(T obj) where T : IDisposable
{
disposeOnOneTimeEnd.Enqueue(obj);
return obj;
}
/// <summary>
/// Pass a function that generates or returns a disposable object that will be cleaned up at the end of the test.
/// </summary>
/// <param name="generator"></param>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
protected T RegisterDisposableOneTimeTestObject<T>(Func<T> generator) where T : IDisposable
{
var obj = generator();
return RegisterDisposableOneTimeTestObject(obj);
}
protected IEnumerator OpenScene(string scenePath, bool isOneTime = false)
{
var asyncOp = SceneManager.LoadSceneAsync(scenePath, LoadSceneMode.Additive);
asyncOp!.completed += SetLoadedSceneActive;
yield return asyncOp;
var loadedScene = SceneManager.GetSceneAt(SceneManager.loadedSceneCount - 1);
if (!isOneTime)
closeOnTestEnd.Push(loadedScene);
else
closeOnOneTimeEnd.Push(loadedScene);
}
protected IEnumerator CloseLatestScene(bool isOneTime = false)
{
var targetStack = !isOneTime ? closeOnTestEnd : closeOnOneTimeEnd;
if (!targetStack.TryPop(out var targetScene))
yield break;
var asyncOp = SceneManager.UnloadSceneAsync(targetScene);
asyncOp!.completed += SetLoadedSceneActive;
yield return asyncOp;
}
protected void SetLoadedSceneActive(AsyncOperation asyncOperation)
{
SceneManager.SetActiveScene(SceneManager.GetSceneAt(SceneManager.loadedSceneCount - 1));
}
[ExcludeFromCoverage]
protected virtual void OneTimeSetUp() { }
[ExcludeFromCoverage]
protected virtual IEnumerator UnityOneTimeSetUp()
{
yield return null;
}
protected virtual void SetUp() { }
protected virtual IEnumerator UnitySetUp()
{
yield return null;
}
protected virtual void TearDown() { }
protected virtual IEnumerator UnityTearDown()
{
yield return null;
}
[ExcludeFromCoverage]
protected virtual void OneTimeTearDown() { }
[ExcludeFromCoverage]
protected virtual IEnumerator UnityOneTimeTearDown()
{
yield return null;
}
/// <summary>
/// Set a private value member of an object via C# reflection.
/// </summary>
/// <example><code>
/// public class SomeObject {
/// private int item;
/// }
///
/// var obj = new SomeObject();
/// SetReflectedValue(obj, "item", 25);
/// </code></example>
private protected void SetReflectedValue(object targetObject, string targetProperty, object targetValue)
{
SetReflectedValue(targetObject, targetObject.GetType(), targetProperty, targetValue);
}
private protected void SetReflectedValues(object targetObject, params ValueTuple<string, object>[] properties)
{
var type = targetObject.GetType();
for (var i = 0; i < properties.Length; i++)
SetReflectedValue(targetObject, type, properties[i].Item1, properties[i].Item2);
}
/// <summary>
/// Set a non-interface reference member of a MonoBehaviour via Unity reflection.
/// Will be applied depending on context of Test setup being used.
/// </summary>
/// <example><code>
/// public class SomeOtherObject { }
///
/// public class SomeObject : MonoBehaviour {
/// private SomeOtherObject item;
/// }
///
/// var gameObj = new GameObject("SomeObj");
/// var c = gameObj.AddComponent(typeof(SomeObject));
/// var someOtherObj = new SomeOtherObj();
///
/// SetObjectReference(c, "item", someOtherObj);
/// </code></example>
private protected void SetObjectReference(Object targetObj, string targetValue, Object value)
{
if (!objectPropertyCache.TryGetValue(targetObj, out var serializedObject))
{
serializedObject = new SerializedObject(targetObj);
objectPropertyCache.Add(targetObj, serializedObject);
}
var property = serializedObject.FindProperty(targetValue);
property.objectReferenceValue = value;
serializedObject.ApplyModifiedProperties();
}
/// <summary>
/// Set a non-interface reference member of a MonoBehaviour via Unity reflection.
/// Will be applied depending on context of Test setup being used.
/// </summary>
/// <example><code>
/// public class SomeObject : MonoBehaviour {
/// private SomeOtherObject item1;
/// private SomeAdditionalObject item2;
/// }
///
/// var gameObj = new GameObject("SomeObj");
/// var c = gameObj.AddComponent(typeof(SomeObject));
///
/// SetObjectReference(c, a);
/// </code></example>
private protected void SetObjectReferences(Object targetObj, params ValueTuple<string, Object>[] properties)
{
for (var i = 0; i < properties.Length; i++)
SetObjectReference(targetObj, properties[i].Item1, properties[i].Item2);
}
private void SetReflectedValue(object targetObject, Type type, string targetProperty, object targetValue)
{
var fieldProperty = type.GetField(targetProperty, BindingFlags.NonPublic | BindingFlags.Instance);
if (fieldProperty == null)
{
Debug.LogWarning($"There is no property {targetProperty} to the target object.");
return;
}
fieldProperty.SetValue(targetObject, targetValue);
}
private void Reset()
{
ResetAllMocks();
CleanupDisposableObjects(disposeOnTestEnd);
CleanupUnityObjects(destroyOnTestEnd);
}
private void CleanupUnityObjects(Queue<Object> unityObjects)
{
if (unityObjects.Count == 0)
return;
while (unityObjects.Count != 0)
{
var temp = unityObjects.Dequeue();
if (temp != null)
Object.DestroyImmediate(temp);
}
}
private void CleanupDisposableObjects(Queue<IDisposable> disposableObjects)
{
if (disposableObjects.Count == 0)
return;
while (disposableObjects.Count != 0)
{
var temp = disposableObjects.Dequeue();
temp?.Dispose();
}
}
[ExcludeFromCoverage]
private void ResetAllMocks()
{
var mocks = GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where(f => f.FieldType == typeof(Mock)).Select(f => (Mock)f.GetValue(this));
foreach (var m in mocks)
m.Reset();
}
// [ExcludeFromCoverage]
// private void Apply(bool isGlobal = false)
// {
// ApplyPropertyCache(objectPropertyCache);
// }
//
// [ExcludeFromCoverage]
// private void ApplyPropertyCache(IDictionary<Object, SerializedObject> cache)
// {
// if (cache.Count == 0)
// return;
//
// foreach (var pair in cache)
// pair.Value.ApplyModifiedProperties();
// }
}
}
-2
View File
@@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: f1863291fabd7fb43837115239feede3
@@ -1,7 +1,7 @@
using System.Collections;
using BracerLib.Utility;
using BracerLib.Utility.Testing;
using NUnit.Framework;
using UnityEngine;
namespace BracerLib.Tests.Utility
{
@@ -2,6 +2,7 @@
using System.Collections;
using System.Collections.Generic;
using BracerLib.Utility;
using BracerLib.Utility.Testing;
using NUnit.Framework;
using UnityEngine;