Как протестировать сопрограммы Unity в Unity Test Runner - PullRequest
2 голосов
/ 07 ноября 2019

В настоящее время я разрабатываю игру для Unity 2019 и C # и использую для нее множество событий и сопрограмм. Сопрограммы необходимы, потому что в них сделано много вычислений, и я не хочу, чтобы игра зависала в это время. Теперь я начал писать модульные тесты, используя Test Runner (режим воспроизведения), а сопрограммы просто не выполняются . Поскольку мне действительно нужно быть уверенным, что они работают должным образом, невозможно просто протестировать «на более высоком уровне».

Я уже попробовал обычный метод StartCoroutine (), который не работает в тестефайл («имя метода не найдено»). Более того, я реорганизовал одну из своих сопрограмм, чтобы она стала обычным пустым методом, и все работало хорошо, и оно прошло тест. Я использовал отладчик Visual Studio, чтобы увидеть, переходит ли он в выполнение сопрограммы, и нет. Таким образом, проблема состоит в том, что сопрограммы не выполняются. Я думал о том, чтобы переместить логику вычислений в другую функцию void и протестировать эту функцию (и пропустить сопрограмму), но я должен быть уверен, что итерации, выполняемые в сопрограмме, также работают (они обычно более сложны, чем в примере).

Это минимальный пример, показывающий общую структуру (обычно выполняется гораздо больше вычислений).

public class MeasuredValues
{
    List<Vector3> slidingWindow; // this is already filled when Normalize() is executed

    public IEnumerator Normalize()
    {
        //find coordinate system origin
        Vector3 originPosition = GetOrigin(); // returns a Vector3
        //normalization
        for (int i = 0; i < slidingWindow.Count; i++)
        {
            yield return null;
            //reset point to be at (0,y,0)
            slidingWindow[i] -= originPosition;
        }
    }
}

В тестовом файле я хочу:

[Test]
public void TestNormalization()
{
    MeasuredValues myMeasuredValues = new MeasuredValues();
    // add many Vector3 to slidingWindow
    // call coroutine
    // assert, that the values are now as expected
}

Я попробовал myMeasuredValues.Normalize() (не сработало, отладчик только что перепрыгнул через него) и StartCoroutine(myMeasuredValues.Normalize) (didnне работает, StartCoroutine не доступен в этом контексте). Наконец, я попытался

    while (test.Normalize().MoveNext())
    {
        yield return null;
    }

, но это никогда не заканчивается, поскольку для MoveNext() никогда не устанавливается значение false. По крайней мере, отладчик подключился к методу сопрограммы.

Есть ли какое-либо легко применимое решение для тестирования моих сопрограмм с помощью Visual Studio или Unity Test Runner без необходимости рефакторинга всей структуры проекта?

1 Ответ

1 голос
/ 07 ноября 2019

Я пытался myMeasuredValues.Normalize() (не сработало, отладчик просто перепрыгнул через него)

, что, конечно, так как вы не запускаете сопрограмму

и StartCoroutine(myMeasuredValues.Normalize) (не работало, StartCoroutine недоступна в этом контексте).

, что связано с StartCoroutine,член MonoBehaviour.


То, что вы могли бы сделать, это иметь ссылку на любой MonoBehaviour в сцене и позволить этому обработать рутину.

Вы можете, например,иметь выделенный класс, например

public class TestRoutineRunner : MonoBehaviour
{
    // implementation of the singleton pattern
    private static TestRoutineRunner instance;

    // Get the reference to instance or create it lazy when needed
    public static TestRoutineRunner Instance
    {
        get
        {
            // if instance already exists and is set return it right way
            if(instance) return instance;

            // otherwise find it in the scene
            instance = FindObjectOfType<TestRoutineRunner>();

            // if it is found in the scene return it now
            if(instance) return instance;

            // otherwise create a new one
            instance = new GameObject("TestRoutineRunner").AddComponent<TestRoutineRunner>();

            return instance;
        }
    }

    // Use this for adding a callback what should be done when the routine finishes
    public void TestRoutine(IEnumerator routine, Action whenDone)
    {
        StartCoroutine(RunRoutine(routine, whenDone));
    }

    private IEnumerator RunRoutine(IEnumerator routine, Action whenDone)
    {
        // runs the routine an wait until it is finished
        yield return routine;

        // execute the callback
        whenDone?.Invoke();
    }
}

, а затем в тестовом скрипте сделать

[Test]
public void TestNormalization()
{
    MeasuredValues myMeasuredValues = new MeasuredValues();

    ...

    // run the routine and pass the assert as callback
    TestRoutineRunner.Instance.TestRoutine(
        myMeasuredValues.Normalize(), 
        // for example as lambda expression
        () =>
        {
            // Assert here
        }
    );

    // or as method call
    TestRoutineRunner.Instance.TestRoutine(myMeasuredValues.Normalize(), AssertNow);
}

private void AssertNow()
{
    // assert here
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...