【发布时间】:2016-06-14 03:56:26
【问题描述】:
我有一个 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()。
【问题讨论】:
-
SaveForWeb 和 SaveForX86 是否需要公开,或者可以将它们设为私有并通过 Save 方法进行测试? UpdateGameState 是否需要从 Save 中调用,看起来 Saving 和 Updating 是两件完全不同的事情……您可以将逻辑推到另一个类中,然后模拟它的交互。您可以将其他测试中的一些逻辑提取到两个测试都调用的通用方法中。这在很大程度上取决于不同方法的好处以及您实际上在谈论多少代码(测试/生产)......
标签: c# unit-testing unity3d nunit nsubstitute