TDD在Unity3D遊戲項目開發中的實踐

顧翔老師做品《軟件測試技術實戰 設計、工具及管理》html

京東購書地址:https://item.jd.com/12082665.html編程

微信購書地址:安全

http://detail.youzan.com/show/goods?alias=3erp1xpd7hmoh&from=wsc&kdtfrom=wsc&sf=wx_sm微信

店鋪二維碼:框架

啄木鳥軟件測試培訓網:www.3testing.com編輯器

本文來自:火龍果軟件工程網工具


0x00 前言性能

關於TDD測試驅動開發的文章已經有不少了,可是在遊戲開發尤爲是使用Unity3D開發遊戲時,卻聽不到特別多關於TDD的聲音。那麼本文就來簡單聊一聊TDD如何在U3D項目中使用以及如何使用U3D 5.3.X以後版本已經集成的單元測試模塊Editor Test Runner。單元測試

0x01 你好,TDD測試

TDD,測試驅動開發改變了咱們常見的工做流程,不要求先寫邏輯代碼,反而要求先完成測試代碼。待測試代碼完成以後,咱們再將目光轉移到邏輯代碼,根據測試的要求,完成邏輯代碼,使之可以經過通過拆分後粒度已經很小的測試。這樣作有什麼好處呢?

要將任務拆分紅可測試的各個測試用例,這就要求咱們在完成邏輯代碼時要將代碼的功能儘量細分,換句話說就是讓一個類/方法只負責單一責任,當這個類/方法須要承擔其餘類型/方法的責任的時候,就須要分解這個類/方法。這就迫使咱們要把程序設計成易於調用和可測試的,即迫使咱們解除軟件中的耦合。

更加適合應對需求的常常性變動。身處遊戲開發行業的從業人員都不可否認的一點即是遊戲開發中需求變動是一件不可避免甚至是必不可少的事情,而基於測試驅動開發的另外一個好處即是一旦由於需求變動而出現bug,可以很快的發現,進而解決問題。

單元測試是一種無價的文檔,它是展現方法或類如何使用的最佳文檔。這份文檔是可編譯、可運行的,而且它保持最新,永遠與代碼同步。

0x02 流程,驅動

爲了進行TDD測試驅動開發,咱們須要瞭解TDD的流程或者說技巧,大致上能夠將其步驟簡單的概括爲:紅燈->綠燈->重構。

可是測試是什麼?測試是誰執行的?測試又是如何驅動開發的呢?下面咱們就經過一個小例子來聊一聊這個問題。

程序是什麼?簡單的說就是一段有預期輸出的代碼。咱們能夠執行這段程序,並得到程序的輸出。而所謂的測試,即是這樣的一段程序,它會自動調用執行另外一段須要被測試的代碼(在這裏咱們依靠一些測試框架來實現,例如針對C#的測試框架NUnit),而且根據輸出的可見結果來驗證某些假設是否成立,例如輸出的結果證實假設成立,則測試經過。

簡單的瞭解了測試以後,咱們經過一個小例子來看看測試驅動開發的思路和流程是怎樣的,而且一探「驅動」的具體含義。

紅燈

下面,咱們就利用NUnit來編寫咱們的第一個測試,來看看測試是如何驅動開發的:

//測試被攻擊以後傷害數值是否和預期值相等
[Test]
public void TakeDamage_BeAttacked_HpEqual()
{
HpComp health = new HpComp();
health.currentHp = 100;

health.TakeDamage(50);

Assert.AreEqual(50f, health.currentHp);

首先能夠看到測試代碼的方法名很長,並且測試名中還包括下劃線來保證咱們不會漏掉關於這個測試的重要信息(被測試的方法_測試進行的條件_預期結果),由於在編寫測試代碼時,可讀性是重要的考量之一。

繼續看測試代碼,咱們如今測試的類是HpComp,它包括一個字段currentHp保存瞭如今的血量值,還有一個方法TakeDamage。最開始咱們會將currentHp初始化爲100,以後調用TakeDamage方法,最後使用NUnit的Assert類所提供的靜態方法AreEqual來斷言假設是否成立,也即判斷是否經過測試。

此時,因爲咱們尚未聲明一個叫HpComp的類來處理和血量相關的邏輯,也沒有一個叫currentHp的字段來保存如今的血量,更沒有一個叫TakeDamage的方法,所以咱們運行這個測試的結果即是失敗。換言之,咱們如今處於紅燈階段。

綠燈

測試寫完了,此時是紅燈,而此時將這個紅燈變成綠燈的要求,便驅使着咱們進行開發。所幸的是,咱們要開發的內容,已經在測試中體現了出來:

1.實現一個叫作HpComp的類

2.爲HpComp增長一個字段currentHp,用來保存如今的血量

3.實現一個叫作TakeDamage的方法,而在這個測試中事實上只要求TakeDamage方法將currentHp的值變成50便可。

只要知足這3點,咱們就能夠很輕易的使紅燈變成綠燈。因此,爲了知足測試條件,咱們能夠十分簡單粗暴的寫出以下的代碼:

public class HpComp
{
public float currentHp;

public void TakeDamage(float damage)
{
this.currentHp = 50f;
}
}

好了,在上面的測試代碼中只要調用TakeDamage方法,currentHp的值便被設置爲了50,和斷言中的預期符合,所以測試經過,狀態也由紅燈變成了綠燈。固然,咱們簡單的實現就經過了第一個測試,此時若是有優化代碼的需求,咱們就須要對代碼進行重構,使得代碼更加乾淨。

再來幾回

咱們的第一個測試用例驅動開發出的代碼顯然知足了第一個測試的需求,可是若是咱們從新回到原點,而且思考一下除了知足第一個測試中提供的數據,咱們的代碼還能作什麼,若是換

//測試被攻擊以後傷害數值是否和預期值相等
[Test]
public void TakeDamage_BeAttacked_HpEqual2()
{
HpComp health = new HpComp();
health.currentHp = 150;

health.TakeDamage(10);

Assert.AreEqual(140f, health.currentHp);
}

一個測試條件結果會變得怎樣呢?

咱們來完成一個新的測試:

這是一個新的測試(暫時叫作測試2),這就意味着TakeDamage方法除了經過第一個測試以外,還必須經過這個新的測試2。此時,咱們最初的TakeDamage的實現,顯然沒法經過測試2,所以測試2是紅燈狀態。

這也就是說,隨着咱們的測試增長,會帶來更多的預期和要求,從而驅動咱們開發出知足這些預期和要求的代碼來。隨着測試2的出現,咱們將TakeDamage方法編程了下面這個樣子:

public void TakeDamage(float damage)
{
this.currentHp -= damage;
}

這樣,它不只經過了測試1,同時也經過了測試2。

可是若是咱們重複上面的流程,提出更多的測試呢?也許咱們還會發現TakeDamage方法可能會出現越界的狀況,或者是輸入不合法的狀況等等。固然,這些均可以經過更多的測試來驅動咱們開發出更健康的代碼。

TDD流程小結

經過上面的小例子,咱們能夠看到TDD的流程或者說開發技巧並不難理解:

編寫一個會失敗的測試,以證實產品中的代碼或功能的缺陷。

編寫符合測試預期的代碼。

重構代碼,若是測試經過了,就能夠選擇重構,目標是使代碼的可讀性更強、減小重複代碼。若是不重構,則能夠開始編寫下一個測試,即重複第4步。

重複以上過程。

0x03 問題,方案

因爲遊戲開發和傳統軟件開發之間的差別,所以在開發遊戲的過程當中編寫單元測試,會面臨兩個主要的問題:

1.遊戲開發中會涉及到不少的I/O操做處理,以及視覺和UI的處理,而這個部分是單元測試中比較難以處理的部分。

2.具體到使用Unity3D開發遊戲,咱們天然而然的但願可以將測試的框架集成到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)。

0x04 實踐,U3D中的單元測試

在Untiy編輯器中寫單元測試:

編寫單元測試用例時,使用的主要是Unity Editor自帶的單元測試模塊,所以單元測試是基於NUnit框架的。

這就要求編寫單元測試時,要引入NUnit.Framework命名空間,且單元測試類要加上[TestFixture]屬性,單元測試方法要加上[Test]屬性,並將測試用例的文件放在Editor文件夾下。

測試用例的編寫結構要遵循3A原則,即Arrange, Act, Assert。

即先要設置測試環境,例如實例化測試類,爲測試類的字段賦值。

以後操做對象,即寫測試的行爲。

最後是斷言某件事情是預期的,即判斷是否經過測試。

下面是一個例子:

using UnityEngine;
using System.Collections;
using NUnit.Framework;

[TestFixture]
public class HpCompTests
{
//測試被攻擊以後傷害數值是否和預期值相等
[Test]
public void TakeDamage_BeAttacked_HpEqual()
{
HpComp health = new HpComp();
health.currentHp = 100;

health.TakeDamage(50);

Assert.AreEqual(50f, health.currentHp);
}
}

完成以後,咱們就能夠打開Unity 5.3.x中集成的單元測試模塊來進行自動化測試了。


好了,本文到此就暫時打住了,以後有新的體驗和想法,還會繼續這個話題的總結,也歡迎各位討論。


顧翔凡言:

不是好的工做會給你帶來好的心情,而是好的心情會給你帶來好的工做。


啄木鳥軟件測試培訓中心,2017年主打課:

各企業可進行裁剪

自動化軟件測試課程(企業內訓 24,000,公開課 2,000/人)

軟件性能測試課程(企業內訓 18,000,公開課 1,500/人)

WEB軟件用戶體驗式測試課程(企業內訓 12,000,公開課 1,000/人)

安卓APP自動化軟件測試課程(企業內訓 24,000,公開課 2,000/人)

問題引導的用戶驗收測試(UAT)課程(企業內訓 12,000,公開課 1,000/人)

嵌入式軟件測試培訓課程(企業內訓 18,000,公開課 1,500/人)

探索式軟件測試課程(企業內訓 12,000,公開課 1,000/人)

APP軟件專項測試課程(企業內訓 12,000,公開課 1,000/人)

WEB軟件安全性測試課程(企業內訓 15,000,公開課 1,200/人)

WEB軟件測試課程(企業內訓 12,000,公開課 1,000/人)

以項目爲導向的敏捷課程方案(

兩天課企業內訓:¥12,000 公開課:¥1,000/

三天課企業內訓:¥18,000公開課:¥1,500/

一週課企業內訓:¥29,000公開課:¥5,000/

四周可企業內訓:¥100,000公開課:¥1,0000/

詳細請參看:http://www.3testing.com/files/class.html或者本微信公衆號

本文分享自微信公衆號 - 軟件測試培訓(iTestTrain)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。

相關文章
相關標籤/搜索