Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by spinnerbox · Mar 02, 2016 at 01:41 PM · unity 5testingnunitmonobehavior

How to make MonoBehavior class testable with NSubstitute?

Ton of games have been made with Unity, Hearthstone, Ori and the Blind Forest etc... and they all seem bullet-proof i.e as if they are 100% bug free. So Blizzard must have used some sort of testing for Hearthstone. I am still struggling to understand how to make a class that inherits MonoBehavior testable. You must create GameObject that will hold a MonoBehavior component.

I have this class:

 using UnityEngine;
 using System;
 using System.Runtime.Serialization.Formatters.Binary;
 using System.IO;
 
 public class SaveLoadGameData : MonoBehaviour
 {
     public static SaveLoadGameData gameState;
 
     public float experience = Helper.DEFAULT_EXPERIENCE;
     public float score = Helper.DEFAULT_SCORE;
 
     void Awake ()
     {
         Init();
     }
 
     public void Init()
     {
         if (gameState == null)
         {
             DontDestroyOnLoad(gameObject);
             gameState = this;
         }
         else if (gameState != this)
         {
             Destroy(gameObject);
         }
     }
 
     public void SaveForWeb ()
     {
         UpdateGameState();
         try
         {
             PlayerPrefs.SetFloat(Helper.EXP_KEY, experience);
             PlayerPrefs.SetFloat(Helper.SCORE_KEY, score);
 
             PlayerPrefs.Save();
         }
         catch (Exception ex)
         {
             Debug.Log(ex.Message);
         }
     }

     public void UpdateGameState ()
     {
         gameState.experience = experience;
         gameState.score = score;
     }
 }
 
 [Serializable]
 class GameData
 {
     public float experience = Helper.DEFAULT_EXPERIENCE;
     public float score = Helper.DEFAULT_SCORE;
 }

I want to check if UpdateGameState() was called when calling SaveForWeb(). There is a tutorial how to do that with NSubstitute here: http://nsubstitute.github.io/help/received-calls/ But it uses Interface and a class constructor that recieves interface.

how would you make my class testable with NSubstitute? Should SaveLoadGameData implement ISaveLoadGameData interface or I create constructor that calls a function inside?

Let me know your ideas.

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

2 Replies

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by spinnerbox · Mar 03, 2016 at 01:12 PM

According to the tutorial for testing MonoBehaviors I made decoupling of the MonoBehavior functionality and the other testable functionality using separate class and an Interface

 using System;
 using UnityEngine;
 
 namespace Assets.Scripts
 {
     /// <summary>
     /// Description of ISaveLoadGameData.
     /// </summary>
     public interface ISaveLoadGameData
     {
         void Init();
         void SaveForWeb();
         void UpdateGameState();
     }
 }
 
 using System;
 using UnityEngine;
 
 namespace Assets.Scripts
 {
     /// <summary>
     /// Description of SaveLoadGameDataController.
     /// </summary>
     [Serializable]
     public class SaveLoadGameDataController : ISaveLoadGameData
     {
         ISaveLoadGameData slgdInterface;
         GameObject gameObject;
 
         public static SaveLoadGameDataController gameState;
 
         public float experience = Helper.DEFAULT_EXPERIENCE;
         public float score = Helper.DEFAULT_SCORE;
 
         public void SetSaveLoadGameData (ISaveLoadGameData slgd)
         {
             slgdInterface = slgd;
         }

         public Init ()
         {
               slgdInterface.Init();
         }
 
         public void SaveForWeb ()
         {
             slgdInterface.SaveForWeb();
         }

         public void UpdateGameState ()
         {
             slgdInterface.UpdateGameState();
         }
     }
 }

This way I was able to make clean and simple tests for Save() function like this:

     [Test]
     [Category(Helper.TEST_CATEGORY_SAVE_FOR_WEB)]
     public void SaveForWebTest_CreateFakeGameStateObjectRunTheFuncAndCheckIfUpdateGameStateIsCalled_PassesIfUpdateGameStateFuncWasCalled ()
     {
         // arrange
         var slgdController = FakeSaveLoadGameDataController();
             
         // act
         slgdController.ClearReceivedCalls();
         slgdController.SaveForWeb();
         
         // assert
         slgdController.Received().UpdateGameState();
     }

Where FakeSaveLoadGameDataController() looks like this:

 SaveLoadGameDataController FakeSaveLoadGameDataController ()
 {
     SaveLoadGameDataController slgdController = Substitute.For<SaveLoadGameDataController>();
     ISaveLoadGameData slgd = Substitute.For<ISaveLoadGameData>();
     slgdController.SetSaveLoadGameData(slgd);
 
     slgdController.experience = Arg.Is<float>(x => x > 0);
     slgdController.score = Arg.Is<float>(x => x > 0);
 
     return slgdController;
 }
Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
1

Answer by phil_me_up · Mar 02, 2016 at 01:53 PM

Have you seen the blog post on the Unity Test Tools: http://blogs.unity3d.com/2014/07/28/unit-testing-at-the-speed-of-light-with-unity-test-tools/

In there they give some examples of how you might achieve this, specifically in the Mock object section.

EDIT: Meant to link to this too, which specifically deals with the problems of testing Monobehaviours: http://blogs.unity3d.com/2014/06/03/unit-testing-part-2-unit-testing-monobehaviours/

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image spinnerbox · Mar 03, 2016 at 01:06 PM 0
Share

Yes the tutorials leaded me to the solution but I cannot accept this as an answer. I will post my own how I solved this.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

58 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

NUnit difference between Assert's IsTrue/IsFalse and True/False 1 Answer

Wait times when developing 3 Answers

Can Unity 5.6's Test Runner optionally output NUnit 2 xml format? 2 Answers

How can I run Unity tests with some defined nUnit category 2 Answers

How to implement mandatory cleanup for the Unity PlayMode tests? 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges