Open3
テスト用Scriptを楽に作る自分用ライブラリ
動機
- Unityからテストスクリプトを生成する手段が面倒
- interface の定義が(自分のプロジェクトでは)似通っており、毎回テストのためにMock的なクラスを作るのが面倒
出来たもの
テストスクリプトの作成
テストはまだ書かんけど、とりあえずファイルだけ作っとこみたいなときに使う。
テストファイルにテストするクラスを書いておくとIDEとかで定義に飛べる。
入力ファイル
Hoge.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Hoge : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
自動生成されるファイル
HogeTest.cs
using NUnit.Framework;
using System.Collections.Generic;
using System.Collections;
using UnityEngine.TestTools;
using UnityEngine;
namespace Tests
{
public class HogeTest
{
Hoge x = default;
// A Test behaves as an ordinary method
[Test]
public void HogeTestSimplePasses()
{
// Use the Assert class to test conditions
}
// A UnityTest behaves like a coroutine in Play Mode. In Edit Mode you can use
// `yield return null;` to skip a frame.
[UnityTest]
public IEnumerator HogeTestWithEnumeratorPasses()
{
// Use the Assert class to test conditions.
// Use yield to skip a frame.
yield return null;
}
}
}
テスト用モックの作成
自分のスタイルだと、IObservable
みたいなプロパティとか SetXXX(value)
UniTask
とかのメソッドを interface に定義することがよくある。
で、テストコード用の interface 実装を毎回作るのが大変だったので、自分がよく使うスタイルに対応して自動生成させる。
Setした結果のプロパティとか IObservable
に連動した Subject
などを公開する。
入力ファイル
IHoge.cs
using System;
using System.Threading;
using Cysharp.Threading.Tasks;
using UniRx;
namespace HappyTesting {
public interface IHoge {
string Hoge { get; }
void SetHoge(string hoge);
IObservable<Unit> HogeObsevable { get; }
IReadOnlyReactiveProperty<int> HogeValue { get; }
UniTask SetFugaPiyoAsync(string fuga, float piyo, CancellationToken cancellationToken);
UniTask<(string, float)> GetFugaPiyoAsync(CancellationToken cancellationToken);
}
}
自動生成されるファイル
HogeMock.cs
using System;
using System.Threading;
using Cysharp.Threading.Tasks;
using UniRx;
namespace HappyTesting.Tests
{
public class HogeTestMock : IHoge
{
public string Hoge { set; get; }public string SetHogeHogeResult { private set; get; }
public void SetHoge(string hoge) {
SetHogeHogeResult = hoge;
}public IObservable<Unit> HogeObsevable => HogeObsevableSubject;
public readonly Subject<Unit> HogeObsevableSubject = new();public IReadOnlyReactiveProperty<int> HogeValue => HogeValueSubject.ToReadOnlyReactiveProperty();
public readonly Subject<int> HogeValueSubject = new();public string SetFugaPiyoAsyncFugaResult { private set; get; }
public float SetFugaPiyoAsyncPiyoResult { private set; get; }
public CancellationToken SetFugaPiyoAsyncCancellationTokenResult { private set; get; }
public async UniTask SetFugaPiyoAsync(string fuga, float piyo, CancellationToken cancellationToken) {
await UniTask.Yield();
SetFugaPiyoAsyncFugaResult = fuga;
SetFugaPiyoAsyncPiyoResult = piyo;
SetFugaPiyoAsyncCancellationTokenResult = cancellationToken;
}public UniTaskCompletionSource<(string, float)> GetFugaPiyoAsyncCts { get; } = new();
public async UniTask<(string, float)> GetFugaPiyoAsync(CancellationToken cancellationToken) {
await UniTask.Yield();
return await GetFugaPiyoAsyncCts.Task;
}
}
}
成形するとこんな感じ
HogeMock.cs
using System;
using System.Threading;
using Cysharp.Threading.Tasks;
using UniRx;
namespace HappyTesting.Tests {
public class HogeTestMock : IHoge {
public string Hoge { set; get; }
public string SetHogeHogeResult { private set; get; }
public void SetHoge(string hoge) {
SetHogeHogeResult = hoge;
}
public IObservable<Unit> HogeObsevable => HogeObsevableSubject;
public readonly Subject<Unit> HogeObsevableSubject = new();
public IReadOnlyReactiveProperty<int> HogeValue => HogeValueSubject.ToReadOnlyReactiveProperty();
public readonly Subject<int> HogeValueSubject = new();
public string SetFugaPiyoAsyncFugaResult { private set; get; }
public float SetFugaPiyoAsyncPiyoResult { private set; get; }
public CancellationToken SetFugaPiyoAsyncCancellationTokenResult { private set; get; }
public async UniTask SetFugaPiyoAsync(string fuga, float piyo, CancellationToken cancellationToken) {
await UniTask.Yield();
SetFugaPiyoAsyncFugaResult = fuga;
SetFugaPiyoAsyncPiyoResult = piyo;
SetFugaPiyoAsyncCancellationTokenResult = cancellationToken;
}
public UniTaskCompletionSource<(string, float)> GetFugaPiyoAsyncCts { get; } = new();
public async UniTask<(string, float)> GetFugaPiyoAsync(CancellationToken cancellationToken) {
await UniTask.Yield();
return await GetFugaPiyoAsyncCts.Task;
}
}
}