UnityTestAttribute.cs 4.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. using System;
  2. using System.Collections;
  3. using NUnit.Framework;
  4. using NUnit.Framework.Internal.Commands;
  5. using NUnit.Framework.Interfaces;
  6. using NUnit.Framework.Internal;
  7. using NUnit.Framework.Internal.Builders;
  8. using UnityEngine.TestRunner.NUnitExtensions.Runner;
  9. namespace 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, ISimpleTestBuilder, IImplyFixture
  61. {
  62. /// <summary>
  63. /// Initializes and returns an instance of UnityTestAttribute.
  64. /// </summary>
  65. public UnityTestAttribute() : base(new UnityCombinatorialStrategy(), new ParameterDataSourceProvider()) {}
  66. private readonly NUnitTestCaseBuilder _builder = new NUnitTestCaseBuilder();
  67. /// <summary>
  68. /// This method builds the TestMethod from the Test and the method info. It also checks if the test with the `UnityTestAttribute` has an IEnumerator as return type.
  69. /// </summary>
  70. /// <param name="method">The method info.</param>
  71. /// <param name="suite">The test.</param>
  72. /// <returns>A TestMethod object</returns>
  73. TestMethod ISimpleTestBuilder.BuildFrom(IMethodInfo method, Test suite)
  74. {
  75. TestCaseParameters parms = new TestCaseParameters
  76. {
  77. ExpectedResult = new object(),
  78. HasExpectedResult = true
  79. };
  80. var t = _builder.BuildTestMethod(method, suite, parms);
  81. if (t.parms != null)
  82. t.parms.HasExpectedResult = false;
  83. if (!method.ReturnType.IsType(typeof(IEnumerator)))
  84. {
  85. t.RunState = RunState.NotRunnable;
  86. t.Properties.Set(PropertyNames.SkipReason, "Method marked with UnityTest must return IEnumerator.");
  87. }
  88. return t;
  89. }
  90. }
  91. }