The document discusses the importance of writing automated tests using the Unity Test Framework, highlighting the benefits of Test-Driven Development (TDD) and providing insights into testing practices for both business logic and user interfaces. It emphasizes the need for effective test practices, exploring challenges and strategies for testing in the 3D environment typical in Unity development. The authors encourage starting automated testing in existing projects gradually while focusing on high-risk or frequently modified code.
Presentation on writing tests with the Unity Test Framework by Harald Reingruber and Peter Kofler, highlighting their backgrounds in Visual Computing and Software Development.
Discusses the importance of writing tests, personal experiences with TDD, and the overall goal of quality assurance in software development.
Explains the advantages of automated testing including risk management, ensuring code changes don't introduce regressions, and scalability of tests across platforms.
Outlines the process of writing tests before production code, benefits and challenges of TDD, and its application in UI and 3D development.
Introduces the Unity Test Framework based on NUnit, including examples of tests, test methods, and the setup and teardown procedures.
Differentiates between Play-mode and Edit-mode tests, outlining when to use each type within the Unity testing environment.
Describes situations encountered during testing, emphasizing the preference for unit tests over integration tests and how to implement scene loading.
Provides strategies for enhancing test performance, including managing real-time tests, utilizing Unity's Input System for user input simulation.
Covers techniques for comparing decimal values and vectors, as well as the benefits of parameterized tests for efficiency.
Notes on challenges faced with testing, from initial learning curves to integrating tests into existing projects.
Guidance on how to start automated testing within teams and existing codebases, along with conclusions on the future benefits of testing.
Wraps up the presentation with a summary of key points discussed, expresses gratitude, and provides further resources for collaboration.
Writing Tests with theUnity Test Framework Harald Reingruber & Peter Kofler @Harald3DCV @codecopkofler
2.
Harald Reingruber ● Workingin Visual Computing industry for 10 years ● Experienced the benefits of having tests ● Thinks bad tests are better than no tests ● Experiments with mob-programming ⇒ https://www.meetup.com/ Mob-Programming-on-Open-Source-Software/
3.
Peter Kofler ● ProfessionalSoftware Developer for 20+ years ● I help development teams with Quality and Productivity ● “Developing Quality Software Developers” ● I run Coding Dojo and Coderetreats ⇒ https://www.softwerkskammer.org/groups/wien
4.
Agenda ● Why WriteTests? ● Unity Test Framework ● Test “Situations” we faced ● How to get started ● QA
5.
What is yourexperience? What is a test? I write tests for most of my business logic. I am using TDD day to day. I am testing also the UI of my applications. I am writing automated tests for ALL THE THINGS ;-)
Why write automatedtests in general? Tests are about getting feedback and managing risk. A big part is the (business) logic and is usually automatic testable. Benefits of automated tests: ● Get feedback during development if your ideas work (TDD) ● Keep features working if code is changed (Regressions) ○ Allow refactoring ○ Return on Investment (ROI) ● Volume (thousands of cases) & scale testing to other platforms, devices, etc. ● Running tests 24/7 (“addicted to feedback”)
8.
Unit- vs. IntegratedTests ● System tests are easier to write (and often the only ones possible) for user interfaces. ● UI tests are much slower, feedback takes longer, tests are run rarely. ● Integrated tests are not aligned with TDD process and have less benefits.
9.
Why write thetest first? When using Test Driven Development you write your test before you write the production code. Pros of TDD: ● Faster feedback of your ideas ● We develop inherently testable code ● We design the production code interface from the viewpoint of calling code ○ encourages modular design with few dependencies Cons: Hard to learn. Doesn’t work well in all cases.
11.
What about writingtests for user interfaces? Graphics and user interface work is a lot of “fiddling” with pixels and coordinates. You must “massage” the code into place. It needs a very rapid cycle of edit-and-run. (Uncle Bob) Most people agree that we are not writing automated tests for ● styles ● colours ● pixel perfect positions ● maybe hard coded text displayed
12.
What about testingin the 3D world? Is it even possible? We would like to have the benefits of automated tests. What about TDD? We tried a sample project, approx. 30 hours pair programming. This talk is about what we learned... Btw: We don’t want to test the graphics engine or the GPU driver.
Based on NUnit Basictest method [Test] public void HelloWorldTest() { // Act var message = new Message(); // Assert Assert.That(message.Text, Is.EqualTo("Hello World")); }
16.
Based on NUnit Arrange- Act - Assert [Test] public void HelloWorldTest() { // Arrange Environment.PrepareStuff(); // Act var message = new Message(); // Assert Assert.That(message.Text, Is.EqualTo("Hello World")); }
17.
Based on NUnit Fixtures [SetUp] publicvoid Init(){ /* ... */ } [TearDown] public void Cleanup(){ /* ... */ } [Test] public void HelloWorldTest() { // Act var message = new Message(); // Assert Assert.That(message.Text, Is.EqualTo("Hello World")); }
18.
Based on NUnit Onetime Fixtures [OneTimeSetUp] public void Init(){ /* ... */ } [OneTimeTearDown] public void Cleanup(){ /* ... */ } [Test] public void HelloWorldTest() { // Act var message = new Message(); // Assert Assert.That(message.Text, Is.EqualTo("Hello World")); }
Unity Test Framework ●Install via the Unity Package Manager ● Play-mode tests ⇒ load scenes and assert run-time behaviour ● Test builds ⇒ run tests on different platforms (mobile, consoles, WebAssembly) https://docs.unity3d.com/Packages/com.unity.test-framework@1.1
21.
Play-mode vs. Edit-modeTest Play-mode Tests ● run standalone in a Player or inside the Editor Edit-mode Tests ● only run in the Unity Editor ● and have access to the Editor code in addition to the game code ⇒ with Edit Mode tests it is possible to test any of your Editor extensions
22.
Play-mode vs. UnitTest Prefer unit tests, i.e. NUnit Test attribute. Use unit tests instead of the UnityTest attribute, unless you need to skip a frame or wait for a certain amount of time (that is unless you need something of the Unity engine). In Play Mode, the UnityTest attribute runs as a coroutine.
Avoid (slow) IntegrationTests It’s tempting to often test with a Integration Test, but it comes at a cost. Pattern: If it’s unclear if a Unit Test is possible, start with an Integration Test first and try to refactor to a unit test later.
25.
public class TestSceneStartup: SceneTestFixture { [UnityTest] public IEnumerator TestSpaceFighter() { yield return LoadScene("SpaceFighter"); // Wait a few seconds to ensure the scene starts correctly yield return new WaitForSeconds(2.0f); } } Scene Loading Zenject (Dependency Injection framework) offers a SceneTestFixture
26.
public static classFind { public static GameObject SingleObjectById(string objectId) { var gameObjects = Object.FindObjectsOfType<Identifier>() .Where(identifier => identifier.id == objectId) .Select(identifier => identifier.gameObject) .ToList(); Assert.That(gameObjects.Count, Is.EqualTo(1), $"Object {objectId} not found"); return gameObjects[0]; } } Query Object by ID We used an Identifier script to query the GameObject from the test. This way, failing tests are avoided when the objects are renamed. Linear search only works for scenes with not many objects.
27.
Slow tests ● Make(real time) tests faster ⇒ tweak Time.timeScale ● Make your tests faster than real-time, but make sure to not execute “unnecessary” things first. ● Watch out for stability… Maybe have a nightly-build with real-time scale as well?
28.
Waiting for somethingto be ready ● We created helper coroutines for better readability. ● Recommendation: Keep the actual test method clean and readable, future maintainers (or future you) will thank you 🙏 yield return Given.Scene("TestEnvironmentScene");
29.
Input Testing The (new)Input System allows to simulate user input. https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/manual/Testing.html [Test] public void TestGamepad() { var gamepad = InputSystem.AddDevice<Gamepad>(); Press(gamepad.buttonSouth); Set(gamepad.leftStick, new Vector2(0.123f, 0.234f)); }
30.
Comparing decimal numbers [Test] publicvoid VerifyThat_TwoFloatsAreEqual() { var comparer = new FloatEqualityComparer(10e-6f); var actual = -0.00009f; var expected = 0.00009f; Assert.That(actual, Is.EqualTo(expected).Using(comparer)); } allowed error
31.
Comparing Vectors [Test] public voidVerifyThat_TwoVector3ObjectsAreEqual() { // Custom error 10e-6f var actual = new Vector3(10e-8f, 10e-8f, 10e-8f); var expected = new Vector3(0f, 0f, 0f); var comparer = new Vector3EqualityComparer(10e-6f); Assert.That(actual, Is.EqualTo(expected).Using(comparer)); } allowed error
32.
Parameterized Test Reduce duplicationand increase test coverage. [Test] public void MyTest([Values(1, 2, 3)] int x, [Values("A", "B")] string s) { /* ... */ } MyTest(1, "A") MyTest(1, "B") MyTest(2, "A") MyTest(2, "B") MyTest(3, "A") MyTest(3, "B")
33.
Parameterized Test Recommendation: Parameters shouldonly test one “dimension”. Don’t merge different “requirements” because it’s easy to do. It will make analyzing a failing test more difficult. Balance test expressiveness vs code reuse.
34.
Bugs we stillsaw Remember the “fiddling” of colours and coordinates? ● We focused on the dynamic coordinates, states etc. ● and ignored the constant values in our tests ● The constant value was wrong ;-) ● E.g. ○ The object did move but had wrong height Needed to run the application and see these bugs
How to startautomated testing in existing projects? In the beginning much time is spent on ● Learning to write tests ● Arguing with team members ● Making the code testable ● Building test infrastructure Expect it to be slow, painful, excruciating ;-) Start slow, time-box a few hours a week. Do not expect to get anywhere soon.
37.
How to starttesting in your team? Communicate the benefits of automated tests ● High complexity code needs tests ● High risk code needs tests ● Discuss trade-offs, avoid dogma Educate yourself and your team on testing techniques ● Go to Coding Dojos and Coderetreats :) ● Try to find good and bad testing patterns, communicate them in the team ● Get help from outside, e.g. Technical Agile Coaching
38.
Where to starttesting in an existing code base? Add tests when changing code ● Create a test for every bug. ● Focus on new developments and refactor and test code when it is changed ● Don’t test “production tested” code which doesn’t need to be changed. Focus on areas and bring them under test ● Focus on high risk code to mitigate business risk. ● Focus on code which is often changed to avoid regressions. Maybe start with code which is easy to test while you are learning.
39.
Conclusion Automated tests payoff in the future. They are a tool to manage risk. Testing 3D components in Unity is possible. Some of the 3D stuff was easy to test. Not all things (on the UI) can be tested nor need to be tested. Without experience it is hard to tell where tests are most beneficial. You need to get started now!