A game about forced loneliness, made by TACStudios
1using System; 2using System.Collections; 3using System.Collections.Generic; 4using NUnit.Framework; 5using NUnit.Framework.Interfaces; 6using NUnit.Framework.Internal; 7using NUnit.Framework.Internal.Builders; 8 9namespace UnityEngine.TestTools 10{ 11 /// <summary> 12 /// `UnityTest` attribute is the main addition to the standard [NUnit](http://www.nunit.org/) library for the Unity Test Framework. This type of unit test allows you to skip a frame from within a test (so background tasks can finish) or give certain commands to the Unity **Editor**, such as performing a domain reload or entering **Play Mode** from an **Edit Mode** test. 13 /// In Play Mode, the `UnityTest` attribute runs as a [coroutine](https://docs.unity3d.com/Manual/Coroutines.html). Whereas Edit Mode tests run in the [EditorApplication.update](https://docs.unity3d.com/ScriptReference/EditorApplication-update.html) callback loop. 14 /// The `UnityTest` attribute is, in fact, an alternative to the `NUnit` [Test attribute](https://github.com/nunit/docs/wiki/Test-Attribute), which allows yielding instructions back to the framework. Once the instruction is complete, the test run continues. If you `yield return null`, you skip a frame. That might be necessary to ensure that some changes do happen on the next iteration of either the `EditorApplication.update` loop or the [game loop](https://docs.unity3d.com/Manual/ExecutionOrder.html). 15 /// <example> 16 /// ## Edit Mode example 17 /// The most simple example of an Edit Mode test could be the one that yields `null` to skip the current frame and then continues to run: 18 /// <code> 19 /// [UnityTest] 20 /// public IEnumerator EditorUtility_WhenExecuted_ReturnsSuccess() 21 /// { 22 /// var utility = RunEditorUtilityInTheBackground(); 23 /// 24 /// while (utility.isRunning) 25 /// { 26 /// yield return null; 27 /// } 28 /// 29 /// Assert.IsTrue(utility.isSuccess); 30 /// } 31 /// </code> 32 /// </example> 33 /// <example> 34 /// ## Play Mode example 35 /// 36 /// In Play Mode, a test runs as a coroutine attached to a [MonoBehaviour](https://docs.unity3d.com/ScriptReference/MonoBehaviour.html). So all the yield instructions available in coroutines, are also available in your test. 37 /// 38 /// From a Play Mode test you can use one of Unity’s [Yield Instructions](https://docs.unity3d.com/ScriptReference/YieldInstruction.html): 39 /// 40 /// - [WaitForFixedUpdate](https://docs.unity3d.com/ScriptReference/WaitForFixedUpdate.html): to ensure changes expected within the next cycle of physics calculations. 41 /// - [WaitForSeconds](https://docs.unity3d.com/ScriptReference/WaitForSeconds.html): if you want to pause your test coroutine for a fixed amount of time. Be careful about creating long-running tests. 42 /// 43 /// The simplest example is to yield to `WaitForFixedUpdate`: 44 /// <code> 45 /// [UnityTest] 46 /// public IEnumerator GameObject_WithRigidBody_WillBeAffectedByPhysics() 47 /// { 48 /// var go = new GameObject(); 49 /// go.AddComponent&lt;Rigidbody&gt;(); 50 /// var originalPosition = go.transform.position.y; 51 /// 52 /// yield return new WaitForFixedUpdate(); 53 /// 54 /// Assert.AreNotEqual(originalPosition, go.transform.position.y); 55 /// } 56 /// </code> 57 /// </example> 58 /// </summary> 59 [AttributeUsage(AttributeTargets.Method)] 60 public class UnityTestAttribute : CombiningStrategyAttribute, IImplyFixture, ISimpleTestBuilder, ITestBuilder, IApplyToTest 61 { 62 private const string k_MethodMarkedWithUnitytestMustReturnIenumerator = "Method marked with UnityTest must return IEnumerator."; 63 64 /// <summary> 65 /// Initializes and returns an instance of UnityTestAttribute. 66 /// </summary> 67 public UnityTestAttribute() : base(new UnityCombinatorialStrategy(), new ParameterDataSourceProvider()) {} 68 69 private readonly NUnitTestCaseBuilder _builder = new NUnitTestCaseBuilder(); 70 71 /// <summary> 72 /// This method builds the TestMethod from the Test and the method info. In addition it removes the expected result of the test. 73 /// </summary> 74 /// <param name="method">The method info.</param> 75 /// <param name="suite">The test.</param> 76 /// <returns>A TestMethod object</returns> 77 TestMethod ISimpleTestBuilder.BuildFrom(IMethodInfo method, Test suite) 78 { 79 var t = CreateTestMethod(method, suite); 80 81 AdaptToUnityTestMethod(t); 82 83 return t; 84 } 85 86 /// <summary> 87 /// This method hides the base method from CombiningStrategyAttribute. 88 /// It builds a TestMethod from a Parameterized Test and the method info. 89 /// In addition it removes the expected result of the test. 90 /// </summary> 91 /// <param name="method">The method info.</param> 92 /// <param name="suite">The test.</param> 93 /// <returns>A TestMethod object</returns> 94 IEnumerable<TestMethod> ITestBuilder.BuildFrom(IMethodInfo method, Test suite) 95 { 96 var testMethods = base.BuildFrom(method, suite); 97 98 foreach (var t in testMethods) 99 { 100 AdaptToUnityTestMethod(t); 101 } 102 103 return testMethods; 104 } 105 106 private TestMethod CreateTestMethod(IMethodInfo method, Test suite) 107 { 108 TestCaseParameters parms = new TestCaseParameters 109 { 110 ExpectedResult = new object(), 111 HasExpectedResult = true 112 }; 113 114 var t = _builder.BuildTestMethod(method, suite, parms); 115 return t; 116 } 117 118 private static void AdaptToUnityTestMethod(TestMethod t) 119 { 120 if (t.parms != null) 121 { 122 t.parms.HasExpectedResult = false; 123 } 124 } 125 126 private static bool IsMethodReturnTypeIEnumerator(IMethodInfo method) 127 { 128 return !method.ReturnType.IsType(typeof(IEnumerator)); 129 } 130 131 /// <summary> 132 /// This method hides the base method ApplyToTest from CombiningStrategyAttribute. 133 /// In addition it ensures that the test with the `UnityTestAttribute` has an IEnumerator as return type. 134 /// </summary> 135 /// <param name="test">The test.</param> 136 public new void ApplyToTest(Test test) 137 { 138 if (IsMethodReturnTypeIEnumerator(test.Method)) 139 { 140 test.RunState = RunState.NotRunnable; 141 test.Properties.Set(PropertyNames.SkipReason, k_MethodMarkedWithUnitytestMustReturnIenumerator); 142 } 143 144 base.ApplyToTest(test); 145 } 146 } 147}