
[英]How to code a switch statement to test DialogResult and provide fall through logic
[英]How to test a function that has only switch logic?
我有一个Save()函数的代码,里面只有switch语句。 因此,基本上可以根据选择的平台进行节省。 但是我已经对UpdateGameState(),SaveForWeb()和SaveForX86()函数进行了测试。 由于单元测试规则说,如果您的函数中有逻辑,无论它多么简单,都必须测试该函数。
public void Save ()
{
switch(Helper.BUILD_TYPE)
{
case Helper.BUILD_FOR_WEB:
SaveForWeb();
break;
case Helper.BUILD_FOR_WIN_X86:
SaveForX86();
break;
default:
Debug.Log("Save method: " + Helper.WRONG_BUILD_TYPE_SELECTED_ERR);
break;
}
}
在测试中调用test也会破坏测试的隔离规则,因此看来我不得不在其他测试中复制测试逻辑,只是为了检查Save()逻辑在SaveForWeb()和SaveForX86()之后是否一直有效。
在这种情况下,您将如何测试此功能?
我可以在测试中做到这一点:
Helper.BUILD_TYPE = Helper.BUILD_FOR_WEB;
其中BUILD_TYPE是静态的,但不是BUILD_FOR_WEB和BUILD_FOR_WIN_X86的常数。
这是要测试的课程:
using UnityEngine;
using System;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
public class SaveLoadGameData : MonoBehaviour
{
public static SaveLoadGameData gameState;
public float experience = Helper.DEFAULT_EXPERIENCE;
public float score = Helper.DEFAULT_SCORE;
void Awake ()
{
Init();
}
public void Init()
{
if (gameState == null)
{
DontDestroyOnLoad(gameObject);
gameState = this;
}
else if (gameState != this)
{
Destroy(gameObject);
}
}
public void SaveForWeb ()
{
UpdateGameState();
try
{
PlayerPrefs.SetFloat(Helper.EXP_KEY, experience);
PlayerPrefs.SetFloat(Helper.SCORE_KEY, score);
PlayerPrefs.Save();
}
catch (Exception ex)
{
Debug.Log(ex.Message);
}
}
public void SaveForX86 ()
{
UpdateGameState();
try
{
BinaryFormatter bf = new BinaryFormatter();
FileStream fs = File.Create(Application.persistentDataPath + Helper.GAME_DATA_FILE_NAME);
GameData data = new GameData();
data.experience = experience;
data.score = score;
bf.Serialize(fs, data);
fs.Close();
}
catch (Exception ex)
{
Debug.Log(ex.Message);
}
}
public void Save ()
{
switch(Helper.BUILD_TYPE)
{
case Helper.BUILD_FOR_WEB:
SaveForWeb();
break;
case Helper.BUILD_FOR_WIN_X86:
SaveForX86();
break;
case Helper.BUILD_FOR_ANDROID:
break;
default:
Debug.Log("Save method: " + Helper.WRONG_BUILD_TYPE_SELECTED_ERR);
break;
}
}
public void LoadForWeb ()
{
try
{
experience = PlayerPrefs.GetFloat(Helper.EXP_KEY, Helper.DEFAULT_EXPERIENCE);
score = PlayerPrefs.GetFloat(Helper.SCORE_KEY, Helper.DEFAULT_SCORE);
}
catch (Exception ex)
{
Debug.Log(ex.Message);
}
}
public void LoadForX86 ()
{
try
{
if (File.Exists(Application.persistentDataPath + Helper.GAME_DATA_FILE_NAME))
{
BinaryFormatter bf = new BinaryFormatter();
FileStream fs = File.Open(Application.persistentDataPath + Helper.GAME_DATA_FILE_NAME, FileMode.Open);
GameData data = (GameData)bf.Deserialize(fs);
experience = data.experience;
score = data.score;
fs.Close();
}
else
{
Save();
}
}
catch (Exception ex)
{
Debug.Log(ex.Message);
}
}
public void Load ()
{
switch(Helper.BUILD_TYPE)
{
case Helper.BUILD_FOR_WEB:
LoadForWeb();
break;
case Helper.BUILD_FOR_WIN_X86:
LoadForX86();
break;
case Helper.BUILD_FOR_ANDROID:
break;
default:
Debug.Log("Load method: " + Helper.WRONG_BUILD_TYPE_SELECTED_ERR);
break;
}
UpdateGameState();
}
public void UpdateGameState ()
{
gameState.experience = experience;
gameState.score = score;
}
public void ResetGameState ()
{
experience = Helper.DEFAULT_EXPERIENCE;
score = Helper.DEFAULT_SCORE;
Save();
}
}
[Serializable]
class GameData
{
public float experience = Helper.DEFAULT_EXPERIENCE;
public float score = Helper.DEFAULT_SCORE;
}
注意:我从Save()中删除了UpdateGameState(),现在它既是SaveForWeb()又是SaveForX86()。
如果已经对UpdateGameState(),SaveForWeb()等进行了测试,则不应“双重”测试逻辑。仅应在设置了不同枚举时验证是否已调用方法。 这意味着保存方法本身可能是它自己的一个类,并且对其他方法依赖一个或多个接口。
根据本测试MonoBehavior的教程,我使用单独的类和接口将MonoBehavior功能与其他可测试功能分离
using System;
using UnityEngine;
namespace Assets.Scripts
{
/// <summary>
/// Description of ISaveLoadGameData.
/// </summary>
public interface ISaveLoadGameData
{
void SaveForWeb();
void SaveForX86();
void Save();
void UpdateGameState();
}
}
using System;
using UnityEngine;
namespace Assets.Scripts
{
/// <summary>
/// Description of SaveLoadGameDataController.
/// </summary>
[Serializable]
public class SaveLoadGameDataController : ISaveLoadGameData
{
ISaveLoadGameData slgdInterface;
GameObject gameObject;
public static SaveLoadGameDataController gameState;
public float experience = Helper.DEFAULT_EXPERIENCE;
public float score = Helper.DEFAULT_SCORE;
public void SetSaveLoadGameData (ISaveLoadGameData slgd)
{
slgdInterface = slgd;
}
public void SaveForWeb ()
{
slgdInterface.SaveForWeb();
}
public void SaveForX86 ()
{
slgdInterface.SaveForX86();
}
public void Save ()
{
slgdInterface.Save();
}
public void UpdateGameState ()
{
slgdInterface.UpdateGameState();
}
}
}
这样,我就可以对Save()函数进行干净而简单的测试,如下所示:
[Test]
[Category(Helper.TEST_CATEGORY_SAVE_GAME_STATE)]
public void SaveTest_SetBuildTypeToWebAndRunSave_PassesIfSaveFunctionCalledSaveForWebFunction ()
{
// arrange
Helper.BUILD_TYPE = Helper.BUILD_FOR_WEB;
var slgdController = FakeSaveLoadGameDataController();
// act
slgdController.ClearReceivedCalls();
slgdController.Save();
// assert
slgdController.Received().SaveForWeb();
}
[Test]
[Category(Helper.TEST_CATEGORY_SAVE_GAME_STATE)]
public void SaveTest_SetBuildTypeToX86AndRunSave_PassesIfSaveFunctionCalledSaveForX86Function ()
{
// arrange
Helper.BUILD_TYPE = Helper.BUILD_FOR_WIN_X86;
var slgdController = FakeSaveLoadGameDataController();
// act
slgdController.ClearReceivedCalls();
slgdController.Save();
// assert
slgdController.Received().SaveForX86();
Helper.BUILD_TYPE = Helper.BUILD_FOR_WEB;
}
FakeSaveLoadGameDataController()如下所示:
SaveLoadGameDataController FakeSaveLoadGameDataController ()
{
SaveLoadGameDataController slgdController = Substitute.For<SaveLoadGameDataController>();
ISaveLoadGameData slgd = Substitute.For<ISaveLoadGameData>();
slgdController.SetSaveLoadGameData(slgd);
slgdController.experience = Arg.Is<float>(x => x > 0);
slgdController.score = Arg.Is<float>(x => x > 0);
return slgdController;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.