Introduction To Unity Unit Testing | raywenderlich.com

Learn all about how Unit Tests in Unity work and how to use them in your projects in this great tutorial.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/9454-introduction-to-unity-unit-testing

Great article, Anthony!
I am starting QA-ing a Unity engine based project and looking for the tool for the integration/ e2e tests. Do you maybe have experience with such tools, can you recommend any? Thank you.

@anthonyuccello Can you please help with this when you get a chance? Thank you - much appreciated! :]

As soon as I create the Assembly in my scripts folder I get ‘type or namespace’ errors. Why?

@anthonyuccello Do you have any feedback about this? Thank you - much appreciated! :]

I believe this article is not technically demonstrating unit testing, but in fact integration testing. More specifically, the “unit tests” here are a form of bottom-up integration testing. The type of test described by the article to be an integration test (i.e. testing in a production environment or simulating a user’s interaction) is more accurately top-down (or “big bang”) integration testing. The primary reason for this observation is that the AsteroidsMoveDown test resembles a simulation, a characteristic of an (albeit automated) integration test. It instantiates a Game Monobehaviour, then an Asteroid object, allows the simulation to run for a time with yield return new WaitForSeconds(...); and validates the resulting environment for the asteroid’s position. This would be an unsurprising format had this test been labeled an integration test. In truth, this “unit test” cannot be distinguished from an integration test which involved the “modules” of an asteroid, game and the game engine itself to validate the functional requirement that asteroids must fall over time.

A few points for those learning to write unit tests, and for those trying to do so in Unity:

  • The “unit” under test should be easily identifiable from looking at the body of the test alone. The above AsteroidsMoveDown test is an example of a hard-to-understand test, despite its triviality, since it is not tested directly by any discernible method(s) under test. In reality the asteroid is moved by the engine as a side effect of yield return new WaitForSeconds(...).
  • A good unit test has minimal setup and teardown. Excessive setup and teardown indicates that the underlying architecture resists being tested, a result of too much coupling. Architectures should be built with testability in mind, and may require restructuring it to improve the issue.
  • Any project can benefit from incorporating unit tests at any point in its lifetime. It provides robustness in newly written code, and can reveal those parts of the existing system that are too tightly coupled and should be improved, thereby allowing easier testing.
  • Avoid unit testing private methods directly. The problem with testing a private method is that such private members should be regarded as implementation details of the class and should not be depended on externally (e.g. by the test suite). Often the private method contains interesting logic worth testing, but consider a solution to extract it to a testable interface, such as in the Humble Object Pattern.
  • Unit tests should be naive. The person writing the unit test should not require intimate knowledge of the implementation under test. This results in test bias, and sidesteps the need to write clean code with simple interfaces. One way to practice this is to have one person write the unit test, and a different person implement the corresponding code under test.
  • Tests should be fast, and complete within milliseconds. Tests with the UnityTest attribute are comparatively slow, depending on how many frames must be simulated, and the timeScale selected. The regular Test attribute should be favored where “waiting for time to pass” is not a requirement for the test.
  • Write unit tests for your code. The AsteroidsMoveDown test appears somewhat to be a test of Unity’s engine, since the tested behavior is a result of the engine calling the Monobehaviour.Update method some number of times. The rationale for mocking is to eliminate such dependencies in a unit test, but this test is exactly dependent on the actual implementation of the engine. By the way, I am not suggesting you should try and mock the Unity engine either, but that there is little value in testing Unity itself.
  • As a general rule, if writing the unit test is painful, this is indication of a separate underlying problem (e.g. with the architecture).

Writing unit tests is itself a skill, as is designing a testable architecture. Poor tests can be written for poor code, which accounts for the sentiment of many who hate writing unit tests. The tests in this article appear to be forced, adding relatively little value in contrast to the effort required to write and maintain them. To the writer’s credit, Unity is notoriously problematic for writing unit tests, due to the extensive coupling between Monobehaviours and the Unity engine itself. The symptoms of unit testing within Unity’s framework are identical to those of any large untested, highly coupled codebase. The difference is that, to the typical user of Unity, Unity’s source code is not available and so should be treated as a “third-party dependency.” Every part of the game that is coupled to the engine (e.g. by deriving from Monobehaviour) inherits the engine’s resistance to being tested. While it may be feasible to leverage unit tests while working with Unity, it is not reasonable to force it on such a reluctant system. I expect a correct approach to decouple the logic under test from the engine, something that is not accomplished if one is invoking the engine with its API, e.g. Instantiate(), GetComponent(), yield return new WaitForSeconds(...), etc.

@riggy97 Can you post a screenshot? Are you missing an import?
Can you double back and follow the steps exactly and confirm the issue you are getting (and share the full error)?

Very interesting perspective Manticore…I wonder what @anthonyuccello would say in response?

Regardless, as someone who has not done any testing in Unity, I found the article very well written and extremely informative. I look forward to learning more about this topic in the future!

Thank you!
Daniel

This tutorial is more than six months old so questions are no longer supported at the moment for it. Thank you!