Skip to content

fedorenkosergiy/Moqunity

Repository files navigation

Moqunity

Moqunity is a wrapper for Unity3d Scripting API.

It helps to increase scripts testability.

It allows to substitute (other words to mock) some code parts in testing context.

Context

Introduction

Context is a class that provides access to particular wrappers such as Time, SystemInfo, Application etc.

Context may be inherited and overridden for a block of code.

//Regular context: Moqunity.Context.Factory.Time behaves the same as UnityEngine.Time
float timeScale = Context.Factory.Time.scale;

//Overridden context: Moqunity.Context.Factory.Time behaves the way you want it to.
//Overridden context is valid inside of a block even if it used implicitly.
using(var context = new TestingContext<MyFactory>())
{
  Context.Factory.Init();
  timeScale = Context.Factory.Time.scale;
}

Unit-test example

Class for testing. Please, don't judge it. This is just an example to help you to get the idea.

using Time = Moqunity.Abstract.UnityEngine.Time;//comment this line to get rid of Moqunity
using UnityEngine;
using System;

public class SimpleTimer : MonoBehaviour
{
    private float fireTime = 0.0f;
    private bool isActive = false;
    private Action fireCallback = null;

    private Time Time { get; } = Moqunity.Context.Factory.Time;//comment this line to get rid of Moqunity

    public void Set(float time, Action callback)
    {
        if (isActive) return;
        fireTime = Time.realtimeSinceStartup + time;
        fireCallback = callback;
        isActive = true;
    }

    private void Update()
    {
        if (!isActive) return;
        if (Time.realtimeSinceStartup >= fireTime)
        {
            fireCallback?.Invoke();
            isActive = false;
        }
    }
}

Unit-tests class

MyTime is a class that provides a way to substitute Time.realtimeSinceStartup value.

MyFactory is a class that privide access to a MyTime instance.

CheckCallbackWasFiredInTime() is a method that tests if the timer fires in time.

CheckCallbackWasNotFiredBeforeTime() is a method that tests if the timer remains not firing before it's time.

using System.Collections;
using UnityEngine.TestTools;
using Moqunity;
using UnityEngine;
using Moqunity.Fake.UnityEngine;
using NUnit.Framework;
using Time = Moqunity.Abstract.UnityEngine.Time;

public class SimpleTimerTests
{
    private GameObject gameObject;

    private class MyTyme : FakeTime
    {
        public float overriddenRealtime;

        public override float realtimeSinceStartup => overriddenRealtime;

        public void SetRealtimeSinceStartup(float value) => overriddenRealtime = value;
    }

    private class MyFactory : TestingFactory
    {
        private readonly Time overriddenTime;

        public MyFactory(Time time) => overriddenTime = time;

        protected override Time CreateTime() => overriddenTime;
    }

    [UnitySetUp]
    public IEnumerator Setup()
    {
        gameObject = new GameObject();
        yield return null;
    }

    [UnityTest]
    public IEnumerator CheckCallbackWasFiredInTime()
    {
        var time = new MyTyme();
        var factory = new MyFactory(time);
        factory.Init();
        using var context = new TestingContext(factory);
        {
            bool wasFired = false;
            var timer = gameObject.AddComponent<SimpleTimer>();
            yield return null;
            timer.Set(10.0f, () => wasFired = true);
            yield return null;
            time.SetRealtimeSinceStartup(10.0f);
            yield return null;
            Assert.IsTrue(wasFired);
            Object.Destroy(timer);
        }
    }

    [UnityTest]
    public IEnumerator CheckCallbackWasNotFiredBeforeTime()
    {
        var time = new MyTyme();
        var factory = new MyFactory(time);
        factory.Init();
        using var context = new TestingContext(factory);
        {
            bool wasFired = false;
            var timer = gameObject.AddComponent<SimpleTimer>();
            yield return null;
            timer.Set(10.0f, () => wasFired = true);
            yield return null;
            time.SetRealtimeSinceStartup(9.99f);
            yield return null;
            Assert.IsFalse(wasFired);
            Object.Destroy(timer);
        }
    }

    [UnityTearDown]
    public IEnumerator TearDown()
    {
        Object.Destroy(gameObject);
        yield return null;
    }
}

Structure

The package is consist of several logical parts

  • Abstract - interfaces that are copies of Unity API equivalents
  • Default - default implementations of interfaces. All of them simply redirect calls to Unity API
  • Fake - implementations of interfaces that are fully virtual and can be used as a base for your context

About

No description, website, or topics provided.

Resources

License

MIT, Unknown licenses found

Licenses found

MIT
LICENSE
Unknown
LICENSE.meta

Stars

Watchers

Forks

Packages

 
 
 

Languages