Alpha测试随笔-橘色肥猫
这个作业属于哪个课程 | 2301-计算机学院-软件工程社区 |
---|---|
这个作业要求在哪里 | 团队作业——站立式会议+alpha冲刺 |
这个作业的目标 | 阅读学习《构建之法》第2章和13章,建立冲刺阶段的测试并行工作。根据不同项目,选择和运用合适的测试工具,并在冲刺过程中逐步展开自动化测试工作。单独发布一篇测试随笔,描述项目的测试工作安排、测试工具选择和运用、测试用例文档、测试体会、项目测试评述。 |
其他参考文献 | … |
团队名称 | 橘色肥猫 |
测试工作安排
在冲刺阶段,我们采用敏捷方法,将测试工作与开发工作并行进行。这意味着在开发新功能的同时,我们也在进行测试。
- 每日站会:团队成员分享他们的进度和面临的测试挑战。
- 周中检查点:中期检查以确认测试进度与开发同步。
- 冲刺回顾:在冲刺结束时,我们评估测试覆盖情况和质量目标。
测试工具的选择和应用
- Unity Test Framework (UTF):
- 我们编写了一系列测试脚本,专门针对游戏中的谜题解决机制和玩家交互。
- Unity Test Runner:
- 集成到Unity编辑器中,用于管理和执行测试用例,提供实时测试结果反馈。
自动化测试的实施
从项目开始,我就计划将自动化测试作为我们测试策略的一部分。我们首先集中在核心游戏功能上,如谜题逻辑的正确性。随着项目的进展,我们逐步扩展到更复杂的场景,如玩家进度保存和加载、多路径解谜等。
测试用例文档
测试文档内容:
- 基础功能测试:验证游戏启动、菜单导航、设置调整等基本功能。
- 谜题逻辑测试:每个谜题都有多个测试用例,验证所有可能的解决方案和错误尝试的反馈。
- 界面和用户体验测试:测试游戏界面的各个元素,如按钮响应、提示显示、动画流畅性等。
测试代码示例
// ...
[UnityTest]
public IEnumerator GameController_Initialization_Test()
{
// 确保 GameController 正确初始化
Assert.IsNotNull(gameController, "GameController is not initialized.");
// 确保依赖的组件也被正确初始化
Assert.IsNotNull(gameController.gameData, "GameData is not initialized.");
Assert.IsNotNull(gameController.linePrefab, "LinePrefab is not initialized.");
Assert.IsNotNull(gameController.ballPrefab, "BallPrefab is not initialized.");
yield return null;
}
[UnityTest]
public IEnumerator DrawLine_Test()
{
// 调用 DrawLine 方法前后进行检查
int initialLineCount = gameController.lineParent.transform.childCount;
gameController.DrawLine();
int postLineCount = gameController.lineParent.transform.childCount;
// 检查是否有新的线条被创建
Assert.IsTrue(postLineCount > initialLineCount, "Lines were not correctly instantiated.");
yield return null;
}
[UnityTest]
public IEnumerator CreateBall_Test()
{
// 调用 CreateBall 方法前后进行检查
int initialBallCount = Object.FindObjectsOfType<Ball>().Length;
gameController.CreateBall();
int postBallCount = Object.FindObjectsOfType<Ball>().Length;
// 检查是否有新的球体被创建
Assert.IsTrue(postBallCount > initialBallCount, "Balls were not correctly instantiated.");
yield return null;
}
[UnityTest]
public IEnumerator GameState_Check_Test()
{
// 初始化一些必要的状态
gameController.Start();
// 模拟游戏状态检查事件
EventHandler.CheckGameStateEvent?.Invoke();
// 验证游戏是否正确识别了结束状态
// 这可能需要对 GameController 类进行一些修改,以便能够测试私有状态
// 例如,添加一个公共方法或属性来获取游戏状态
// Assert.IsTrue(gameController.IsGameOver, "Game did not recognize the game over state correctly.");
yield return null;
}
using System.Collections;
using System.Collections.Generic;
using NUnit.Framework;
using UnityEngine;
using UnityEngine.TestTools;
using UnityEngine.SceneManagement;
public class NewTestScript
{
// A Test behaves as an ordinary method
[Test]
public void NewTestScriptSimplePasses()
{
// 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 NewTestScriptWithEnumeratorPasses()
{
// Use the Assert class to test conditions.
// Use yield to skip a frame.
yield return null;
}
[UnityTest]
public IEnumerator TransitionToScene_LoadsCorrectScene()
{
// 创建一个GameObject并添加TransitionManager组件
GameObject go = new GameObject();
TransitionManager transitionManager = go.AddComponent<TransitionManager>();
// 模拟场景过渡
yield return transitionManager.TransitionToScene("CurrentScene", "NextScene");
// 验证是否加载了正确的场景
Scene activeScene = SceneManager.GetActiveScene();
Assert.AreEqual("NextScene", activeScene.name);
// 清理
SceneManager.UnloadSceneAsync("NextScene");
GameObject.Destroy(go);
}
[UnityTest]
public IEnumerator TransitionToScene_FadeEffect()
{
// 创建一个GameObject并添加TransitionManager组件
GameObject go = new GameObject();
TransitionManager transitionManager = go.AddComponent<TransitionManager>();
// 模拟场景过渡
yield return transitionManager.TransitionToScene("CurrentScene", "NextScene");
// 验证淡入效果
Assert.AreEqual(0f, transitionManager.fadeCanvasGroup.alpha);
// 等待一帧以确保淡入效果完成
// 验证淡出效果
Assert.AreEqual(1f, transitionManager.fadeCanvasGroup.alpha);
// 清理
SceneManager.UnloadSceneAsync("NextScene");
GameObject.Destroy(go);
}
[Test]
public void CheckItem_CorrectItem_NotDone()
{
// Arrange
var interactive = new GameObject().AddComponent<Interactive>();
interactive.requireItem = ItemName.ItemA;
// Act
interactive.CheckItem(ItemName.ItemA);
// Assert
Assert.IsTrue(interactive.isDone);
}
[Test]
public void CheckItem_WrongItem_NotDone()
{
// Arrange
var interactive = new GameObject().AddComponent<Interactive>();
interactive.requireItem = ItemName.ItemA;
// Act
interactive.CheckItem(ItemName.ItemB);
// Assert
Assert.IsFalse(interactive.isDone);
}
[Test]
public void CheckItem_AlreadyDone_NotDone()
{
// Arrange
var interactive = new GameObject().AddComponent<Interactive>();
interactive.requireItem = ItemName.ItemA;
interactive.isDone = true;
// Act
interactive.CheckItem(ItemName.ItemA);
// Assert
Assert.IsFalse(interactive.isDone);
}
[Test]
public void EmptyClicked_LogsMessage()
{
// Arrange
var interactive = new GameObject().AddComponent<Interactive>();
var logCollector = new LogCollector();
// Act
interactive.EmptyClicked();
// Assert
Assert.AreEqual("空点", logCollector.LastLog);
}
public IEnumerator CursorManager_HandPositionUpdated()
{
// Arrange
var cursorManager = new GameObject().AddComponent<CursorManager>();
cursorManager.hand = new GameObject().AddComponent<RectTransform>();
// Act
yield return null; // Wait for one frame to allow Unity to update
// Assert
Assert.AreEqual(Input.mousePosition, cursorManager.hand.position);
}
[Test]
public void CursorManager_ClickAction_TeleportTag_TeleportToSceneCalled()
{
// Arrange
var cursorManager = new GameObject().AddComponent<CursorManager>();
var teleportObject = new GameObject();
teleportObject.tag = "Teleport";
// Act
cursorManager.clickAction(teleportObject);
// Assert
Assert.IsTrue(teleportObject.GetComponent<Teleport>().teleportCalled);
}
[Test]
public void CursorManager_ClickAction_ItemTag_ItemClickedCalled()
{
// Arrange
var cursorManager = new GameObject().AddComponent<CursorManager>();
var itemObject = new GameObject();
itemObject.tag = "Item";
// Act
cursorManager.clickAction(itemObject);
// Assert
Assert.IsTrue(itemObject.GetComponent<Item>().itemClickedCalled);
}
[Test]
public void CursorManager_ClickAction_InteractiveTag_HoldItem_CheckItemCalled()
{
// Arrange
var cursorManager = new GameObject().AddComponent<CursorManager>();
var interactiveObject = new GameObject();
interactiveObject.tag = "Interactive";
cursorManager.holdItem = true;
// Act
cursorManager.clickAction(interactiveObject);
// Assert
Assert.IsTrue(interactiveObject.GetComponent<Interactive>().checkItemCalled);
}
[Test]
public void CursorManager_ClickAction_InteractiveTag_NotHoldItem_EmptyClickedCalled()
{
// Arrange
var cursorManager = new GameObject().AddComponent<CursorManager>();
var interactiveObject = new GameObject();
interactiveObject.tag = "Interactive";
cursorManager.holdItem = false;
// Act
cursorManager.clickAction(interactiveObject);
// Assert
Assert.IsTrue(interactiveObject.GetComponent<Interactive>().emptyClickedCalled);
}
}
文档示例
-
目的
- 验证
GameController
类在游戏运行期间的各项功能是否正常工作。
- 验证
-
测试范围
-
初始化测试:验证游戏开始时所有必要的组件是否被正确初始化。
-
DrawLine 方法测试:检查是否正确地在预定位置绘制线条。
-
CreateBall 方法测试:确保球体在正确的位置被创建。
-
游戏状态检查测试:验证游戏能否正确判断并处理游戏结束的状态。
-
-
测试方法
-
使用 Unity 的测试框架进行自动化测试。
-
对于每个测试用例,创建一个独立的测试函数。
-
使用模拟数据来代替实际的游戏数据。
-
-
预期结果
-
在所有测试情况下,
GameController
类的方法应按预期执行。 -
游戏应能正确处理初始化、线条绘制、球体创建和游戏状态检查。
-
-
测试后的行动
-
若所有测试通过,则
GameController
类可视为符合要求。 -
若有测试失败,则需要进行调试和修改,直至所有测试通过。
测试结果示例
- 测试测试失败
- 测试测试成功
测试体会和评述
-
测试工作的重要性
- 测试不仅仅是软件开发的一个阶段,而是一个与整个开发过程并行的持续活动。在冲刺阶段,将测试工作与开发工作同步进行,帮助我们在早期发现并修正错误,这对于提高软件质量至关重要。此外,测试不仅限于查找错误,它还涉及到验证产品功能是否满足用户需求和设计规格。
-
选择合适的测试工具
- 我们选择了 Unity Test Framework 和 Unity Test Runner,因为这些工具与我们的开发环境完全集成,使我们能够轻松地编写、运行和监视测试结果。这些工具为我们提供了强大的自动化测试能力,这对于管理复杂的游戏逻辑和交互至关重要。
-
测试用例的编写和执行
- 我们的测试用例涵盖了从基础功能到更复杂的游戏逻辑和用户交互。通过持续更新和维护测试用例,我们确保了测试的有效性和相关性。自动化测试的应用极大地提高了我们的测试效率,使我们能夏集中精力解决更复杂的问题。
-
遇到的挑战
- 我们在实现自动化测试时遇到了一些挑战,特别是在模拟复杂游戏场景和用户交互方面。此外,保持测试用例与不断演进的游戏逻辑同步,也是一个持续的挑战。
-
测试评述
- 我们的测试策略有效地支持了冲刺阶段的开发工作。我们能够快速反馈游戏中的问题,并保证了游戏的稳定性和质量。通过测试,我们也更好地理解了游戏的不同方面,这有助于我们在未来的开发中做出更明智的决策。
结论
总体而言,测试工作在我们的项目中发挥了关键作用。我们建立了一个高效的测试流程,这不仅提高了我们的产品质量,提升了我们团队的技能和知识。合适的测试工具的选择和有效的测试策略对于软件开发项目的成功至关重要。