-
-
Notifications
You must be signed in to change notification settings - Fork 137
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Basic configuration tests to: - Confirm required serialized variables have been initialized - Confirm game objects in a particular scene are on the correct layer - Confirm prefabs are on the correct layer * Substantially refactored configuration testing code. Specifying not-null fields and mandatory layers no longer occurs within DataSource.cs. Rather, attributes have been created to decorate those fields / classes directly, and these are accessed in the test through reflection. * Extracted duplicate code from mandated layer checks. * Editor Tests moved into Scripts folder.
- Loading branch information
Showing
15 changed files
with
300 additions
and
9 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
{ | ||
"name": "EditorTests", | ||
"rootNamespace": "", | ||
"references": [ | ||
"UnityEngine.TestRunner", | ||
"UnityEditor.TestRunner", | ||
"SS3D.Core", | ||
"FishNet.Runtime" | ||
], | ||
"includePlatforms": [ | ||
"Editor" | ||
], | ||
"excludePlatforms": [], | ||
"allowUnsafeCode": false, | ||
"overrideReferences": true, | ||
"precompiledReferences": [ | ||
"nunit.framework.dll" | ||
], | ||
"autoReferenced": false, | ||
"defineConstraints": [ | ||
"UNITY_INCLUDE_TESTS" | ||
], | ||
"versionDefines": [], | ||
"noEngineReferences": false | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,188 @@ | ||
using NUnit.Framework; | ||
using UnityEditor.SceneManagement; | ||
using System.Reflection; | ||
using UnityEngine; | ||
using System; | ||
using UnityEditor; | ||
using System.Text; | ||
|
||
public class LobbyTests | ||
{ | ||
#region Class variables | ||
/// <summary> | ||
/// The name and path of the Scene that this script is testing. | ||
/// </summary> | ||
private const string SCENE_PATH = "Assets/Scenes/Lobby.unity"; | ||
|
||
/// <summary> | ||
/// All of the prefabs in the project. | ||
/// </summary> | ||
private GameObject[] allPrefabs; | ||
|
||
/// <summary> | ||
/// All of the MonoBehaviours in the current scene. | ||
/// </summary> | ||
private MonoBehaviour[] allMonoBehaviours; | ||
|
||
#endregion | ||
|
||
#region Test set up | ||
[OneTimeSetUp] | ||
public void SetUp() | ||
{ | ||
EditorSceneManager.OpenScene(SCENE_PATH); | ||
LoadAllPrefabs(); | ||
LoadAllMonoBehaviours(); | ||
} | ||
|
||
private void LoadAllPrefabs() | ||
{ | ||
// Find all the prefabs in the project hierarchy (i.e. NOT in a scene) | ||
string[] guids = AssetDatabase.FindAssets("t:prefab"); | ||
|
||
// Create our array of prefabs | ||
allPrefabs = new GameObject[guids.Length]; | ||
|
||
// Populate the array | ||
for (int i = 0; i <guids.Length; i++) | ||
{ | ||
allPrefabs[i] = AssetDatabase.LoadAssetAtPath <GameObject>(AssetDatabase.GUIDToAssetPath(guids[i])); | ||
} | ||
} | ||
|
||
private void LoadAllMonoBehaviours() | ||
{ | ||
// Find all the Monobehaviours in the currently open scene | ||
allMonoBehaviours = GameObject.FindObjectsOfType<MonoBehaviour>(); | ||
} | ||
#endregion | ||
|
||
#region Tests | ||
|
||
/// <summary> | ||
/// Test to confirm that MonoBehaviours have serialized fields (marked by NotNullAttribute) initialized. | ||
/// The purpose of this test is to prevent NullReferenceExceptions caused by failing to initialize MonoBehaviour fields. | ||
/// </summary> | ||
[Test] | ||
public void SpecifiedFieldsWithinSceneAreNotNull() | ||
{ | ||
|
||
// ARRANGE | ||
bool allRelevantFieldsHaveBeenSet = true; | ||
BindingFlags flags = GetBindingFlags(); | ||
StringBuilder sb = new StringBuilder(); | ||
|
||
// ACT - Check each MonoBehaviour in the scene | ||
foreach (MonoBehaviour mono in allMonoBehaviours) | ||
{ | ||
// Get all fields from the MonoBehaviour using reflection | ||
Type monoType = mono.GetType(); | ||
FieldInfo[] objectFields = monoType.GetFields(flags); | ||
|
||
// Check the fields to see if they have a NotNullAttribute | ||
for (int i = 0; i < objectFields.Length; i++) | ||
{ | ||
NotNullAttribute attribute = Attribute.GetCustomAttribute(objectFields[i], typeof(NotNullAttribute)) as NotNullAttribute; | ||
if (attribute != null) | ||
{ | ||
// Once we are here, we have found a MonoBehaviour field with a NotNullAttribute. | ||
// We now need to test the field to see if it is a value set. | ||
var fieldValue = objectFields[i].GetValue(mono); | ||
|
||
if (fieldValue == null || fieldValue.ToString() == "null") | ||
{ | ||
// The test will fail, as the MonoBehaviour SHOULD have had some value in the required field, but DID NOT. | ||
// We are delaying the assertion so that all errors are identified in the console, rather than requiring the | ||
// test to be run multiple times (and only identifying a single breach each time). | ||
allRelevantFieldsHaveBeenSet = false; | ||
sb.Append($"-> Scene object '{mono.gameObject.name}' does not have {objectFields[i].Name} field set in {monoType.Name} script.\n"); | ||
} | ||
} | ||
} | ||
} | ||
|
||
// ASSERT | ||
Assert.IsTrue(allRelevantFieldsHaveBeenSet, sb.ToString()); | ||
} | ||
|
||
/// <summary> | ||
/// Test to confirm that GameObjects within the tested scene are on the correct layers. | ||
/// The purpose of this test is to ensure layer-based collisions, raycasts, rendering etc function correctly. | ||
/// </summary> | ||
[Test] | ||
public void SpecifiedMonoBehavioursWithinSceneAreOnTheirMandatedLayers() | ||
{ | ||
|
||
// ARRANGE | ||
bool allRelevantMonoBehavioursAreOnTheRightLayer = true; | ||
StringBuilder sb = new StringBuilder(); | ||
|
||
// ACT | ||
allRelevantMonoBehavioursAreOnTheRightLayer = CheckMonoBehavioursForCorrectLayer(allMonoBehaviours, ref sb); | ||
|
||
// ASSERT | ||
Assert.IsTrue(allRelevantMonoBehavioursAreOnTheRightLayer, sb.ToString()); | ||
} | ||
|
||
/// <summary> | ||
/// Test to confirm that prefabs within the project are on the correct layers. | ||
/// The purpose of this is to ensure that any prefabs instantiated at runtime are added to the correct layer. | ||
/// </summary> | ||
[Test] | ||
public void SpecifiedMonoBehavioursWithinPrefabsAreOnTheirMandatedLayers() | ||
{ | ||
|
||
// ARRANGE | ||
bool allRelevantMonoBehavioursAreOnTheRightLayer = true; | ||
StringBuilder sb = new StringBuilder(); | ||
MonoBehaviour[] prefabMonoBehaviours; | ||
|
||
// ACT | ||
foreach (GameObject prefab in allPrefabs) | ||
{ | ||
prefabMonoBehaviours = prefab.GetComponentsInChildren<MonoBehaviour>(); | ||
allRelevantMonoBehavioursAreOnTheRightLayer = | ||
allRelevantMonoBehavioursAreOnTheRightLayer && CheckMonoBehavioursForCorrectLayer(prefabMonoBehaviours, ref sb); | ||
} | ||
|
||
// ASSERT | ||
Assert.IsTrue(allRelevantMonoBehavioursAreOnTheRightLayer, sb.ToString()); | ||
} | ||
#endregion | ||
|
||
#region Helper functions | ||
private BindingFlags GetBindingFlags() | ||
{ | ||
BindingFlags flags = BindingFlags.Public | | ||
BindingFlags.Instance | | ||
BindingFlags.NonPublic; | ||
return flags; | ||
} | ||
|
||
private bool CheckMonoBehavioursForCorrectLayer(MonoBehaviour[] monos, ref StringBuilder sb) | ||
{ | ||
bool allRelevantMonoBehavioursAreOnTheRightLayer = true; | ||
foreach (MonoBehaviour mono in monos) | ||
{ | ||
Type monoType = mono.GetType(); | ||
RequiredLayerAttribute attribute = Attribute.GetCustomAttribute(monoType, typeof(RequiredLayerAttribute)) as RequiredLayerAttribute; | ||
if (attribute != null) | ||
{ | ||
// Once we are here, we have found a MonoBehaviour with a RequiredLayerAttribute. | ||
// We now need to test the GameObject to see if it is on the layer that is mandated. | ||
|
||
if (mono.gameObject.layer != LayerMask.NameToLayer(attribute.layer)) | ||
{ | ||
// The test will fail, as the GameObject SHOULD have had been on a specific layer, but WAS NOT. | ||
// We are delaying the assertion so that all errors are identified in the console, rather than requiring the | ||
// test to be run multiple times (and only identifying a single breach each time). | ||
allRelevantMonoBehavioursAreOnTheRightLayer = false; | ||
sb.Append($"-> {monoType.Name} script requires object '{mono.gameObject.name}' to be on {attribute.layer} layer, but it was on {LayerMask.LayerToName(mono.gameObject.layer)} layer.\n"); | ||
} | ||
} | ||
} | ||
return allRelevantMonoBehavioursAreOnTheRightLayer; | ||
} | ||
|
||
#endregion | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
using System; | ||
|
||
/// <summary> | ||
/// When decorated with this attribute, a field requires that it be set | ||
/// to a non-null value prior to runtime. It should not be used on fields | ||
/// that you intend to initialize at runtime. | ||
/// </summary> | ||
[AttributeUsage(AttributeTargets.Field)] | ||
public class NotNullAttribute : Attribute | ||
{ | ||
|
||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
using System; | ||
|
||
/// <summary> | ||
/// When decorated with this attribute, a Component requires that its GameObject | ||
/// is on the specified layer. | ||
/// </summary> | ||
[AttributeUsage(AttributeTargets.Class)] | ||
public class RequiredLayerAttribute : Attribute | ||
{ | ||
public readonly string layer; | ||
|
||
public RequiredLayerAttribute(string layer) | ||
{ | ||
this.layer = layer; | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters