ExtPlayerPrefs のテストコード

目的

この資料は、ExtPlayerPrefs クラスの機能を網羅的にテストするコードの内容と、その背景を説明するものです。


テストの概要

ExtPlayerPrefs クラスのテストコードは、以下の機能を確認することを目的としています:

  1. プリミティブ型データの保存と読み出しが正しく行われること。
  2. 複雑なオブジェクトの保存と復元が期待通り動作すること。
  3. ScriptableObject の保存・読み出しが適切に処理されること。
  4. エラー処理が正しく動作し、適切な例外がスローされること。

テストの内容

1. プリミティブ型データの保存と読み出し

テストケース

  1. 整数型 (int) の同期保存と読み出し
  2. 文字列型 (string) の非同期保存と読み出し

実装例

[Test]
public void SaveAndLoad_PrimitiveInt_ShouldWorkCorrectly()
{
    int testValue = 42;
    ExtPlayerPrefs.Save(testValue, TestFileName, EncryptionKey);
    var loadedValue = ExtPlayerPrefs.Load<int>(TestFileName, EncryptionKey);
    Assert.AreEqual(testValue, loadedValue);
}

[Test]
public async Task SaveAndLoadAsync_PrimitiveString_ShouldWorkCorrectly()
{
    string testValue = "Hello, World!";
    await ExtPlayerPrefs.SaveAsync(testValue, TestFileName, EncryptionKey);
    var loadedValue = await ExtPlayerPrefs.LoadAsync<string>(TestFileName, EncryptionKey);
    Assert.AreEqual(testValue, loadedValue);
}

確認ポイント

  • 保存した値と読み出した値が完全に一致するか。
  • ファイルが正しく生成されるか。
  • 非同期処理が正常に完了するか。

2. 複雑なオブジェクトの保存と読み出し

テストケース

  1. カスタムクラス TestData の同期保存と読み出し
  2. 非同期処理によるデータ保存と復元

実装例

[Test]
public void SaveAndLoad_ShouldWorkCorrectly()
{
    var testData = new TestData { Name = "TestUser", Age = 25 };
    ExtPlayerPrefs.Save(testData, TestFileName, EncryptionKey);
    var loadedData = ExtPlayerPrefs.Load<TestData>(TestFileName, EncryptionKey);
    Assert.AreEqual(testData.Name, loadedData.Name);
    Assert.AreEqual(testData.Age, loadedData.Age);
}

[Test]
public async Task SaveAndLoadAsync_ShouldWorkCorrectly()
{
    var testData = new TestData { Name = "AsyncUser", Age = 30 };
    await ExtPlayerPrefs.SaveAsync(testData, TestFileName, EncryptionKey);
    var loadedData = await ExtPlayerPrefs.LoadAsync<TestData>(TestFileName, EncryptionKey);
    Assert.AreEqual(testData.Name, loadedData.Name);
    Assert.AreEqual(testData.Age, loadedData.Age);
}

確認ポイント

  • オブジェクトのプロパティが保存前後で一致しているか。
  • 非同期処理が期待通り動作するか。

3. ScriptableObject の保存と読み出し

テストケース

  1. ScriptableObject の同期保存と読み出し
  2. 非同期処理による ScriptableObject の保存と復元

実装例

[Test]
public void SaveScriptableObjectAndLoadScriptableObject_ShouldWorkCorrectly()
{
    var myObject = ScriptableObject.CreateInstance<MyScriptableObject>();
    myObject.Description = "Test Description";
    myObject.Value = 99;

    ExtPlayerPrefs.SaveScriptableObject(myObject, TestFileName, EncryptionKey);

    var loadedObject = ScriptableObject.CreateInstance<MyScriptableObject>();
    ExtPlayerPrefs.LoadScriptableObject(loadedObject, TestFileName, EncryptionKey);

    Assert.AreEqual(myObject.Description, loadedObject.Description);
    Assert.AreEqual(myObject.Value, loadedObject.Value);
}

[Test]
public async Task SaveScriptableObjectAsyncAndLoadScriptableObjectAsync_ShouldWorkCorrectly()
{
    var myObject = ScriptableObject.CreateInstance<MyScriptableObject>();
    myObject.Description = "Async Test Description";
    myObject.Value = 99;

    await ExtPlayerPrefs.SaveScriptableObjectAsync(myObject, TestFileName, EncryptionKey);

    var loadedObject = ScriptableObject.CreateInstance<MyScriptableObject>();
    await ExtPlayerPrefs.LoadScriptableObjectAsync(loadedObject, TestFileName, EncryptionKey);

    Assert.AreEqual(myObject.Description, loadedObject.Description);
    Assert.AreEqual(myObject.Value, loadedObject.Value);
}

確認ポイント

  • ScriptableObject のプロパティが保存前後で一致しているか。
  • 非同期処理による保存・読み出しが正常に動作するか。

4. エラーハンドリング

テストケース

  1. 存在しないファイルを読み込もうとした場合
  2. null データを保存しようとした場合

実装例

[Test]
public void Load_NonExistentFile_ShouldThrowFileNotFoundException()
{
    Assert.Throws<FileNotFoundException>(() =>
    {
        ExtPlayerPrefs.Load<int>("non_existent.json");
    });
}

[Test]
public void Save_NullObject_ShouldThrowArgumentNullException()
{
    Assert.Throws<System.ArgumentNullException>(() =>
    {
        ExtPlayerPrefs.Save<string>(null, TestFileName, EncryptionKey);
    });
}

確認ポイント

  • 適切な例外がスローされるか (FileNotFoundExceptionArgumentNullException)。
  • 不正な操作によるシステムエラーが発生しないか。

テストコード全体の設計意図

  1. 網羅性
    • ExtPlayerPrefs の全機能(プリミティブ型、複雑な型、ScriptableObject)をカバー。
    • 同期処理・非同期処理の両方をテスト。
  2. 信頼性
    • 保存前後のデータ一致を厳密に検証。
    • ファイル操作における異常系を徹底的にチェック。
  3. 拡張性
    • 新しいデータ型や機能を追加する際も、このテストを基盤として容易に検証を追加可能。

テストの実行方法

  1. Unityエディタでテスト実行:
    • Window > General > Test Runner を開き、Edit Mode または Play Mode テストを選択。
    • 対象のテストを実行して結果を確認。
  2. テスト結果の確認:
    • 成功時: すべてのテストが緑色で表示されます。
    • 失敗時: エラーが発生したテストが赤色で表示され、失敗の詳細を確認できます。

結論

このテストコードは、ExtPlayerPrefs クラスの全機能を網羅し、実際の運用で信頼性の高い動作を保証するものです。

  • 対応範囲:
    • プリミティブ型(intstring など)
  • 複雑な型(クラス、オブジェクト)
    • Unity特有の型(ScriptableObject
  • 検証内容:
    • 正常系(保存・読み出し)
    • 異常系(エラー処理)

本テストコードを基に、ExtPlayerPrefs の信頼性を高め、Unityプロジェクトでのデータ管理を強化できます。

参考)全テストコード

Assert.AreEqualメソッドは、最新のAssert.Thatを使うようにしています

using NUnit.Framework;
using UnityEngine;
using System.IO;
using System.Threading.Tasks;
using UnityEngine.TestTools;

namespace HKUtility.Tests
{
    public class ExtPlayerPrefsTests
    {
        private const string TestFileName = "test_data.json";
        private const string TestScriptableObjectFileName = "test_scriptable_object.json";
        private const string EncryptionKey = "test_key";
        private string testFilePath;

        [SetUp]
        public void SetUp()
        {
            testFilePath = Path.Combine(Application.persistentDataPath, TestFileName);
            if (File.Exists(testFilePath))
            {
                File.Delete(testFilePath);
            }

            string scriptableObjectPath = Path.Combine(Application.persistentDataPath, TestScriptableObjectFileName);
            if (File.Exists(scriptableObjectPath))
            {
                File.Delete(scriptableObjectPath);
            }
        }

        [TearDown]
        public void TearDown()
        {
            if (File.Exists(testFilePath))
            {
                File.Delete(testFilePath);
            }

            string scriptableObjectPath = Path.Combine(Application.persistentDataPath, TestScriptableObjectFileName);
            if (File.Exists(scriptableObjectPath))
            {
                File.Delete(scriptableObjectPath);
            }
        }

        [Test]
        public void SaveAndLoad_ShouldWorkCorrectly()
        {
            var testData = new TestData { Name = "TestUser", Age = 25 };

            // Save the data
            var savedJson = ExtPlayerPrefs.Save(testData, TestFileName, EncryptionKey);
            Assert.That(savedJson, Is.Not.Null);
            Assert.That(File.Exists(testFilePath), Is.True);

            // Load the data
            var loadedData = ExtPlayerPrefs.Load<TestData>(TestFileName, EncryptionKey);
            Assert.That(loadedData, Is.Not.Null);
            Assert.That(loadedData.Name, Is.EqualTo(testData.Name));
            Assert.That(loadedData.Age, Is.EqualTo(testData.Age));
        }

        [Test]
        public async Task SaveAndLoadAsync_ShouldWorkCorrectly()
        {
            var testData = new TestData { Name = "AsyncUser", Age = 30 };

            // Save the data asynchronously
            var savedJson = await ExtPlayerPrefs.SaveAsync(testData, TestFileName, EncryptionKey);
            Assert.That(savedJson, Is.Not.Null);
            Assert.That(File.Exists(testFilePath), Is.True);

            // Load the data asynchronously
            var loadedData = await ExtPlayerPrefs.LoadAsync<TestData>(TestFileName, EncryptionKey);
            Assert.That(loadedData, Is.Not.Null);
            Assert.That(loadedData.Name, Is.EqualTo(testData.Name));
            Assert.That(loadedData.Age, Is.EqualTo(testData.Age));
        }

        [Test]
        public void SaveScriptableObjectAndLoadScriptableObject_ShouldWorkCorrectly()
        {
            var scriptableObject = ScriptableObject.CreateInstance<TestScriptableObject>();
            scriptableObject.Description = "Test Description";
            scriptableObject.Value = 42;

            // Save ScriptableObject
            var savedJson = ExtPlayerPrefs.SaveScriptableObject(scriptableObject, TestScriptableObjectFileName, EncryptionKey);
            Assert.That(savedJson, Is.Not.Null);
            Assert.That(File.Exists(Path.Combine(Application.persistentDataPath, TestScriptableObjectFileName)), Is.True);

            // Load ScriptableObject
            var loadedObject = ScriptableObject.CreateInstance<TestScriptableObject>();
            ExtPlayerPrefs.LoadScriptableObject(loadedObject, TestScriptableObjectFileName, EncryptionKey);

            Assert.That(loadedObject.Description, Is.EqualTo(scriptableObject.Description));
            Assert.That(loadedObject.Value, Is.EqualTo(scriptableObject.Value));
        }

        [Test]
        public async Task SaveScriptableObjectAsyncAndLoadScriptableObjectAsync_ShouldWorkCorrectly()
        {
            var scriptableObject = ScriptableObject.CreateInstance<TestScriptableObject>();
            scriptableObject.Description = "Async Test Description";
            scriptableObject.Value = 99;

            // Save ScriptableObject asynchronously
            var savedJson = await ExtPlayerPrefs.SaveScriptableObjectAsync(scriptableObject, TestScriptableObjectFileName, EncryptionKey);
            Assert.That(savedJson, Is.Not.Null);
            Assert.That(File.Exists(Path.Combine(Application.persistentDataPath, TestScriptableObjectFileName)), Is.True);

            // Load ScriptableObject asynchronously
            var loadedObject = ScriptableObject.CreateInstance<TestScriptableObject>();
            await ExtPlayerPrefs.LoadScriptableObjectAsync(loadedObject, TestScriptableObjectFileName, EncryptionKey);

            Assert.That(loadedObject.Description, Is.EqualTo(scriptableObject.Description));
            Assert.That(loadedObject.Value, Is.EqualTo(scriptableObject.Value));
        }

        [Test]
        public void Load_NonExistentFile_ShouldThrowFileNotFoundException()
        {
            Assert.That(() => ExtPlayerPrefs.Load<TestData>("non_existent.json"), Throws.TypeOf<FileNotFoundException>());
        }

        [Test]
        public void Save_NullObject_ShouldThrowArgumentNullException()
        {
            Assert.That(() => ExtPlayerPrefs.Save<TestData>(null, TestFileName), Throws.TypeOf<System.ArgumentNullException>());
        }

        [Test]
        public void SaveScriptableObject_Null_ShouldThrowArgumentNullException()
        {
            Assert.That(() => ExtPlayerPrefs.SaveScriptableObject<TestScriptableObject>(null, TestScriptableObjectFileName), Throws.TypeOf<System.ArgumentNullException>());
        }

        [System.Serializable]
        private class TestData
        {
            public string Name;
            public int Age;
        }

        [System.Serializable]
        private class TestScriptableObject : ScriptableObject
        {
            public string Description;
            public int Value;
        }
    }
}

テスト

Posted by hidepon