Testing a Component's Startup

I have a component I want to unit test. I wrote two unit tests, they get run and fail. Debugging them seems to show that adding the component to a game object does not trigger the component’s Start() method (where the logic I’m testing is). How do I test my Start() method (making Start() public and calling it manually is not an option)?

This is my component:

public class CameraAspectRatioLockScr : MonoBehaviour
{
    public Camera ParentCamera { get; private set; }

    void Start ()
    {
        this.ParentCamera = this.gameObject.GetComponentInParent<Camera>();

        if (this.ParentCamera == null)
        {
            throw new MissingComponentException("CameraAspectRatioLockScr failed to find a Camera component in its parent.");
        }
    }
}

These are my unit tests

namespace UnityTest
{
    [TestFixture]
    public class CameraAspectRatioLockTests
    {
        private GameObject SetUpCamera()
        {
            var parentCamera = new GameObject();
            parentCamera.AddComponent<Camera>();

            return parentCamera;
        }

        [Test]
        public void ComponentFindsParentCamera()
        {
            var parentCamera = this.SetUpCamera();

            var subject = parentCamera.AddComponent<CameraAspectRatioLockScr>();

            Assert.IsNotNull(subject.ParentCamera);
        }

        [Test]
        public void ComponentThrowsExceptionWhenParentCameraNotFound()
        {
            var parentObject = new GameObject();

            Assert.Throws<MissingComponentException> (()=>parentObject.AddComponent<CameraAspectRatioLockScr>());
        }
    }
}

I think start will not get called until the next frame, while you are testing on this frame. Try awake or onenable.

Hmm… I tried it and neither OnEnable nor Awake help. I wouldn’t imagine frames would have anything to do with component instantiation, would they?

Can I somehow trigger Unity to poke the Start() method? Is there a specific method I can call to make Unity initialize the component?

You can just make it public and call it yourself directly if you want- the “special functions” are found and added to a list in the background using reflection and it apparently ignores the accessibility of the function.

More importantly, I don’t see where you’re actually making anything a parent of anything else. Am I blind and missing it? GetComponentInParent isn’t actually going to return anything with no parent.

Awake should be called before the next line of code is run after AddComponent.

Start will not be called until immediately before a components first frame. So you would need to make your unit test a coroutine and wait one frame before checking the assertion.

As a general note calls to GetComponent normally belong in Awake instead of Start.

Alternatively you could call Start yourself using reflection. This strikes me as messy.

Lack of a decent unit testing framework is considered a draw back of Unity by many.

I tried awake already and don’t want to make Start public. My temporary solution is to add a protected class inside my unit test file that inherits from my component that has a method void Start that calls base.Start(). That seems to work and shouldn’t pollute my solution with too many classes. The unit test solution I’ll sacrifice to class-pollution I guess :smile: