No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

UnityTestAttribute.cs 6.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using NUnit.Framework;
  5. using NUnit.Framework.Internal.Commands;
  6. using NUnit.Framework.Interfaces;
  7. using NUnit.Framework.Internal;
  8. using NUnit.Framework.Internal.Builders;
  9. using UnityEngine.TestRunner.NUnitExtensions.Runner;
  10. namespace UnityEngine.TestTools
  11. {
  12. /// <summary>
  13. /// `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.
  14. /// 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.
  15. /// 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).
  16. /// <example>
  17. /// ## Edit Mode example
  18. /// 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:
  19. /// <code>
  20. /// [UnityTest]
  21. /// public IEnumerator EditorUtility_WhenExecuted_ReturnsSuccess()
  22. /// {
  23. /// var utility = RunEditorUtilityInTheBackground();
  24. ///
  25. /// while (utility.isRunning)
  26. /// {
  27. /// yield return null;
  28. /// }
  29. ///
  30. /// Assert.IsTrue(utility.isSuccess);
  31. /// }
  32. /// </code>
  33. /// </example>
  34. /// <example>
  35. /// ## Play Mode example
  36. ///
  37. /// 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.
  38. ///
  39. /// From a Play Mode test you can use one of Unity’s [Yield Instructions](https://docs.unity3d.com/ScriptReference/YieldInstruction.html):
  40. ///
  41. /// - [WaitForFixedUpdate](https://docs.unity3d.com/ScriptReference/WaitForFixedUpdate.html): to ensure changes expected within the next cycle of physics calculations.
  42. /// - [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.
  43. ///
  44. /// The simplest example is to yield to `WaitForFixedUpdate`:
  45. /// <code>
  46. /// [UnityTest]
  47. /// public IEnumerator GameObject_WithRigidBody_WillBeAffectedByPhysics()
  48. /// {
  49. /// var go = new GameObject();
  50. /// go.AddComponent&lt;Rigidbody&gt;();
  51. /// var originalPosition = go.transform.position.y;
  52. ///
  53. /// yield return new WaitForFixedUpdate();
  54. ///
  55. /// Assert.AreNotEqual(originalPosition, go.transform.position.y);
  56. /// }
  57. /// </code>
  58. /// </example>
  59. /// </summary>
  60. [AttributeUsage(AttributeTargets.Method)]
  61. public class UnityTestAttribute : CombiningStrategyAttribute, ISimpleTestBuilder, IImplyFixture, ITestBuilder, IApplyToTest
  62. {
  63. const string k_MethodMarkedWithUnitytestMustReturnIenumerator = "Method marked with UnityTest must return IEnumerator.";
  64. /// <summary>
  65. /// Initializes and returns an instance of UnityTestAttribute.
  66. /// </summary>
  67. public UnityTestAttribute() : base(new UnityCombinatorialStrategy(), new ParameterDataSourceProvider()) {}
  68. private readonly NUnitTestCaseBuilder _builder = new NUnitTestCaseBuilder();
  69. /// <summary>
  70. /// This method builds the TestMethod from the Test and the method info. In addition it removes the expected result of the test.
  71. /// </summary>
  72. /// <param name="method">The method info.</param>
  73. /// <param name="suite">The test.</param>
  74. /// <returns>A TestMethod object</returns>
  75. TestMethod ISimpleTestBuilder.BuildFrom(IMethodInfo method, Test suite)
  76. {
  77. var t = CreateTestMethod(method, suite);
  78. AdaptToUnityTestMethod(t);
  79. return t;
  80. }
  81. /// <summary>
  82. /// This method hides the base method from CombiningStrategyAttribute.
  83. /// It builds a TestMethod from a Parameterized Test and the method info.
  84. /// In addition it removes the expected result of the test.
  85. /// </summary>
  86. /// <param name="method">The method info.</param>
  87. /// <param name="suite">The test.</param>
  88. /// <returns>A TestMethod object</returns>
  89. IEnumerable<TestMethod> ITestBuilder.BuildFrom(IMethodInfo method, Test suite)
  90. {
  91. var testMethods = base.BuildFrom(method, suite);
  92. foreach (var t in testMethods)
  93. {
  94. AdaptToUnityTestMethod(t);
  95. }
  96. return testMethods;
  97. }
  98. TestMethod CreateTestMethod(IMethodInfo method, Test suite)
  99. {
  100. TestCaseParameters parms = new TestCaseParameters
  101. {
  102. ExpectedResult = new object(),
  103. HasExpectedResult = true
  104. };
  105. var t = _builder.BuildTestMethod(method, suite, parms);
  106. return t;
  107. }
  108. static void AdaptToUnityTestMethod(TestMethod t)
  109. {
  110. if (t.parms != null)
  111. {
  112. t.parms.HasExpectedResult = false;
  113. }
  114. }
  115. static bool IsMethodReturnTypeIEnumerator(IMethodInfo method)
  116. {
  117. return !method.ReturnType.IsType(typeof(IEnumerator));
  118. }
  119. /// <summary>
  120. /// This method hides the base method ApplyToTest from CombiningStrategyAttribute.
  121. /// In addition it ensures that the test with the `UnityTestAttribute` has an IEnumerator as return type.
  122. /// </summary>
  123. /// <param name="test">The test.</param>
  124. public new void ApplyToTest(Test test)
  125. {
  126. if (IsMethodReturnTypeIEnumerator(test.Method))
  127. {
  128. test.RunState = RunState.NotRunnable;
  129. test.Properties.Set(PropertyNames.SkipReason, k_MethodMarkedWithUnitytestMustReturnIenumerator);
  130. }
  131. base.ApplyToTest(test);
  132. }
  133. }
  134. }