發(fā)布時間:2024-04-13 11:11:00 瀏覽量:190次
前言
關于TDD測試驅動開發(fā)的文章已經有很多了,但是在游戲開發(fā)尤其是使用Unity3D開發(fā)游戲時,卻聽不到特別多關于TDD的聲音。那么本文就來簡單聊一聊TDD如何在U3D項目中使用以及如何使用U3D 5.3.X之后版本已經集成的單元測試模塊Editor Test Runner。
你好,TDD
TDD,測試驅動開發(fā)改變了我們常見的工作流程,不要求先寫邏輯代碼,反而要求先完成測試代碼。待測試代碼完成之后,我們再將目光轉移到邏輯代碼,根據測試的要求,完成邏輯代碼,使之能夠通過經過拆分后粒度已經很小的測試。這樣做有什么好處呢?
要將任務拆分成可測試的各個測試用例,這就要求我們在完成邏輯代碼時要將代碼的功能盡可能細分,換句話說就是讓一個類/方法只負責單一責任,當這個類/方法需要承擔其他類型/方法的責任的時候,就需要分解這個類/方法。這就迫使我們要把程序設計成易于調用和可測試的,即迫使我們解除軟件中的耦合。
更加適合應對需求的經常性變更。身處游戲開發(fā)行業(yè)的從業(yè)人員都不能否認的一點便是游戲開發(fā)中需求變更是一件不可避免甚至是必不可少的事情,而基于測試驅動開發(fā)的另一個好處便是一旦因為需求變更而出現bug,能夠很快的發(fā)現,進而解決問題。
單元測試是一種無價的文檔,它是展示方法或類如何使用的最佳文檔。這份文檔是可編譯、可運行的,并且它保持最新,永遠與代碼同步。
流程,驅動
為了進行TDD測試驅動開發(fā),我們需要了解TDD的流程或者說技巧,大體上可以將其步驟簡單的歸納為:紅燈->綠燈->重構。
但是測試是什么?測試是誰執(zhí)行的?測試又是如何驅動開發(fā)的呢?下面我們就通過一個小例子來聊一聊這個問題。
程序是什么?簡單的說就是一段有預期輸出的代碼。我們可以執(zhí)行這段程序,并獲得程序的輸出。而所謂的測試,便是這樣的一段程序,它會自動調用執(zhí)行另一段需要被測試的代碼(在這里我們依靠一些測試框架來實現,例如針對C#的測試框架NUnit),并且根據輸出的可見結果來驗證某些假設是否成立,例如輸出的結果證明假設成立,則測試通過。
簡單的了解了測試之后,我們通過一個小例子來看看測試驅動開發(fā)的思路和流程是怎樣的,并且一探“驅動”的具體含義。
紅燈
下面,我們就利用NUnit來編寫我們的第一個測試,來看看測試是如何驅動開發(fā)的:
//測試被攻擊之后傷害數值是否和預期值相等
[Test]
public void TakeDamage_BeAttacked_HpEqual
{
HpComp health = new HpComp;
health.currentHp = 100;
health.TakeDamage(50);
Assert.AreEqual(50f, health.currentHp);
}
復制代碼
首先可以看到測試代碼的方法名很長,而且測試名中還包括下劃線來保證我們不會漏掉關于這個測試的重要信息(被測試的方法_測試進行的條件_預期結果),因為在編寫測試代碼時,可讀性是重要的考量之一。
繼續(xù)看測試代碼,我們現在測試的類是HpComp,它包括一個字段currentHp保存了現在的血量值,還有一個方法TakeDamage。最開始我們會將currentHp初始化為100,之后調用TakeDamage方法,最后使用NUnit的Assert類所提供的靜態(tài)方法AreEqual來斷言假設是否成立,也即判斷是否通過測試。
此時,由于我們還沒有聲明一個叫HpComp的類來處理和血量相關的邏輯,也沒有一個叫currentHp的字段來保存現在的血量,更沒有一個叫TakeDamage的方法,因此我們運行這個測試的結果便是失敗。換言之,我們現在處于紅燈階段。
綠燈
測試寫完了,此時是紅燈,而此時將這個紅燈變成綠燈的要求,便驅使著我們進行開發(fā)。所幸的是,我們要開發(fā)的內容,已經在測試中體現了出來:
實現一個叫做HpComp的類;
為HpComp增加一個字段currentHp,用來保存現在的血量;
實現一個叫做TakeDamage的方法,而在這個測試中事實上只要求TakeDamage方法將currentHp的值變成50即可。
只要滿足這3點,我們就可以很輕易的使紅燈變成綠燈。所以,為了滿足測試條件,我們可以十分簡單粗暴的寫出如下的代碼:
public class HpComp
{
public float currentHp;
public void TakeDamage(float damage)
{
this.currentHp = 50f;
好了,在上面的測試代碼中只要調用TakeDamage方法,currentHp的值便被設置為了50,和斷言中的預期符合,因此測試通過,狀態(tài)也由紅燈變成了綠燈。當然,我們簡單的實現就通過了第一個測試,此時如果有優(yōu)化代碼的需求,我們就需要對代碼進行重構,使得代碼更加干凈。
再來幾次
我們的第一個測試用例驅動開發(fā)出的代碼顯然滿足了第一個測試的需求,但是如果我們重新回到原點,并且思考一下除了滿足第一個測試中提供的數據,我們的代碼還能做什么,如果換一個測試條件結果會變得怎樣呢?
我們來完成一個新的測試:
public void TakeDamage_BeAttacked_HpEqual2
health.currentHp = 150;
health.TakeDamage(10);
Assert.AreEqual(140f, health.currentHp);
這是一個新的測試(暫時叫做測試2),這就意味著TakeDamage方法除了通過第一個測試之外,還必須通過這個新的測試2。此時,我們最初的TakeDamage的實現,顯然無法通過測試2,因此測試2是紅燈狀態(tài)。
這也就是說,隨著我們的測試增加,會帶來更多的預期和要求,從而驅動我們開發(fā)出滿足這些預期和要求的代碼來。隨著測試2的出現,我們將TakeDamage方法編程了下面這個樣子:
this.currentHp -= damage;
這樣,它不僅通過了測試1,同時也通過了測試2。
但是如果我們重復上面的流程,提出更多的測試呢?也許我們還會發(fā)現TakeDamage方法可能會出現越界的情況,或者是輸入不合法的情況等等。當然,這些都可以通過更多的測試來驅動我們開發(fā)出更健康的代碼。
TDD流程小結
通過上面的小例子,我們可以看到TDD的流程或者說開發(fā)技巧并不難理解:
編寫一個會失敗的測試,以證明產品中的代碼或功能的缺陷。
編寫符合測試預期的代碼。
重構代碼,如果測試通過了,就可以選擇重構,目標是使代碼的可讀性更強、減少重復代碼。如果不重構,則可以開始編寫下一個測試,即重復第4步。
重復以上過程。
問題,方案
由于游戲開發(fā)和傳統(tǒng)軟件開發(fā)之間的差異,因此在開發(fā)游戲的過程中編寫單元測試,會面臨兩個主要的問題:
1.游戲開發(fā)中會涉及到很多的I/O操作處理,以及視覺和UI的處理,而這個部分是單元測試中比較難以處理的部分。
2.具體到使用Unity3D開發(fā)游戲,我們自然而然的希望能夠將測試的框架集成到Unity3D的編輯器中,這樣更加容易操作。
針對問題1,由于對I/O處理以及UI視覺方面的操作比較難以實施單元測試,所以我們單元測試的主要對象是邏輯操作以及數據存取的部分。
針對問題2,Unity5.3.x已經在editor中集成了測試模塊。該測試模塊依托了NUnit框架(NUnit是一個單元測試框架,專門針對于.NET來寫的.其實在前面有JUnit(Java),CPPUnit(C++),他們都是xUnit的一員.最初,它是從JUnit而來.U3d使用的版本是2.6.4)。
而且除了Unity5.3.x自帶的單元測試模塊之外,Unity游戲方還推出了一款測試插件Unity Test Tool(基于NSubstitute)。
實踐,U3D中的單元測試
在Untiy編輯器中寫單元測試:
編寫單元測試用例時,使用的主要是Unity Editor自帶的單元測試模塊,因此單元測試是基于NUnit框架的。
這就要求編寫單元測試時,要引入NUnit.Framework命名空間,且單元測試類要加上[TestFixture]屬性,單元測試方法要加上[Test]屬性,并將測試用例的文件放在Editor文件夾下。
測試用例的編寫結構要遵循3A原則,即Arrange, Act, Assert。
即先要設置測試環(huán)境,例如實例化測試類,為測試類的字段賦值。
之后操作對象,即寫測試的行為。
最后是斷言某件事情是預期的,即判斷是否通過測試。
下面是一個例子:
using UnityEngine;
using System.Collections;
using NUnit.Framework;
[TestFixture]
public class HpCompTests
完成之后,我們就可以打開Unity 5.3.x中集成的單元測試模塊來進行自動化測試了。
TDD在Unity3D游戲項目開發(fā)中的實踐
好了,本文到此就暫時打住了,之后有新的體驗和想法,還會繼續(xù)這個話題的總結,也歡迎各位討論。
熱門資訊
探討游戲引擎的文章,介紹了10款游戲引擎及其代表作品,涵蓋了RAGE Engine、Naughty Dog Game Engine、The Dead Engine、Cry Engine、Avalanche Engine、Anvil Engine、IW Engine、Frostbite Engine、Creation引擎、Unreal Engine等引擎。借此分析引出了游戲設計領域和數字藝術教育的重要性,歡迎點擊咨詢報名。
2. 手機游戲如何開發(fā)(如何制作傳奇手游,都需要準備些什么?)
?如何制作傳奇手游,都需要準備些什么?提到傳奇手游相信大家都不陌生,他是許多80、90后的回憶;從起初的端游到現在的手游,說明時代在進步游戲在更新,更趨于方便化移動化。而如果我們想要制作一款傳奇手游的
3. B站視頻剪輯軟件「必剪」:免費、炫酷特效,小白必備工具
B站視頻剪輯軟件「必剪」,完全免費、一鍵制作炫酷特效,適合新手小白??靵碓囋嚕?/span>
游戲中玩家將面臨武俠人生的掙扎抉擇,戰(zhàn)或降?殺或放?每個抉定都將觸發(fā)更多愛恨糾葛的精彩奇遇。《天命奇御》具有多線劇情多結局,不限主線發(fā)展,高自由...
5. Bigtime加密游戲經濟體系揭秘,不同玩家角色的經濟活動
Bigtime加密游戲經濟模型分析,探討游戲經濟特點,幫助玩家更全面了解這款GameFi產品。
6. 3D動漫建模全過程,不是一般人能學的會的,會的多不是人?
步驟01:面部,頸部,身體在一起這次我不準備設計圖片,我從雕刻進入。這一次,它將是一種純粹關注建模而非整體繪畫的形式。像往常一樣,我從Sphere創(chuàng)建它...
7. 3D動畫軟件你知道幾個?3ds Max、Blender、Maya、Houdini大比拼
當提到3D動畫軟件或動畫工具時,指的是數字內容創(chuàng)建工具。它是用于造型、建模以及繪制3D美術動畫的軟件程序。但是,在3D動畫軟件中還包含了其他類型的...
想讓你的3D打印模型更堅固?不妨嘗試一下Cura參數設置和設計技巧,讓你輕松掌握!
?三昧動漫對于著名ARPG游戲《巫師》系列,最近CD Projekt 的高層回應并不會推出《巫師4》。因為《巫師》系列在策劃的時候一直定位在“三部曲”的故事框架,所以在游戲的出品上不可能出現《巫師4》
10. 虛幻引擎5節(jié)省存儲空間用這招!緩存的清理與設置
眾所周知,虛幻引擎5(下面簡稱UE5)特別占用存儲空間,僅一個版本安裝好的文件就有60G,這還不包括我們在使用時保存的工程文件和隨之產生的緩存文件。而...
最新文章
同學您好!