1. 程式人生 > 其它 >【Beta階段】計劃階段要求 - 技術規格說明書 - 靈境 | week12

【Beta階段】計劃階段要求 - 技術規格說明書 - 靈境 | week12

專案 內容
這個作業屬於哪個課程 2022春季軟體工程(羅傑 任健)
這個作業的要求在哪裡 團隊專案-計劃階段要求

Part1 架構與技術棧

1.1 整體架構

本專案的整體架構如上圖所示。

下面我們將對涉及的技術棧進行詳細說明:

1.2 客戶端框架

採用基於C#的Unity框架及其內建各種功能外掛進行安卓客戶端設計。Unity提供一整套完善的軟體解決方案 ,可用於創作、運營和變現任何實時互動的2D和3D內容,支援平臺包括手機、平板電腦、PC、遊戲主機、增強現實和虛擬現實裝置。

1.3 服務端框架

採用SpringBoot+Mybatis-Plus進行主資料庫和快取資料庫的管理,同時融合Websocket+Netty提供高併發網路服務。

SpringBoot背靠Spring和Java社群,可以一鍵快速搭建Spring框架,簡化初始配置 ,可與許多主流第三方開源框架進行結合。

使用Unity內建Mirror框架進行Unity多人3D場景線上同步功能實現。

1.4 資料庫

採用了MySQL資料庫,服務端使用Mybatis-Plus包實現MVC架構,通過對映前端的資料到DTO層,資料庫的資料對映到DOMAIN層,返回給前端的資料對映到VO層來對資料進行高效管理。同時,輔助使用Redis進行資料快取。

1.5 雲環境

採用了阿里雲提供的輕量應用伺服器,具體配置如下:

映象:Ubuntu 20.04 LTS

運算元件:2核CPU、4GB記憶體

雲SSD系統盤:50GB SSD雲硬碟

流量包:1200GB流量包

Part2 設計與分析

2.1 系統層面

2.1.1 程式碼設計

  • 功能模組化

    • 客戶端

      對於客戶端來說,我們要構建出一個包含許多場景的應用,每個場景都有屬於自己的功能。因此,需要每個場景都是獨立的,這樣模組化的設計方式使得不管是前期的開發還是後期的測試都更加便捷

    • 後端(遊戲後端和資料後端)

      由於應用更貼近於遊戲的需求,因此將後端分為遊戲後端和資料後端也是一種功能模組化的方式,遊戲後端主要負責多人同步,資料後端主要負責資料管理

  • 資料抽象化

    • 對於模型,將每個模型儲存在資料後端,而模型資料的傳遞依靠其對應的URL,在最終需要渲染的場合再通過URL向資料後端請求模型,減少了資料傳遞的複雜度
    • 對於其他使用者資料,後端將所有需要的資料進行封裝,以整體的形式傳遞給前端,減少了多次傳輸的消耗

2.1.2 架構設計

  • 介面和實現的分離

    總體來說,我們專案中包含了客戶端、遊戲後端、資料後端。客戶端是呈現給使用者的介面,即為前端的設計。而考慮到我們的前端有類似於遊戲的多人線上同步的需求,普通的後端無法滿足該需求,所以我們採用了遊戲後端與資料後端分離的設計,客戶端在獲取使用者相關的資料時,將向資料後端傳送請求,而在獲取遊戲相關的資料則與遊戲後端進行溝通。

  • 錯誤處理

    對於客戶端,錯誤發生在unity的程式碼邏輯上。這一部分錯誤可以在測試階段通過多次測試發現並修改在程式碼上,同時在產品釋出後,可以針對反饋資訊來進行錯誤的收集。

    對於遊戲後端,錯誤主要發生在伺服器網路上,包括了網路傳輸出錯、伺服器效能等錯誤行為,這大部分是不可抗力的問題,我們可以採用出錯時更完善地處理錯誤,防止使用者掉線等情況的出現。

    對於資料後端,錯誤發生在資料的處理上,包括了資料不存在,許可權失敗等錯誤行為,這些錯誤可以在測試階段進行捕獲。另一方面,有些錯誤是系統允許的,需要對使用者的非法行為做出應對,屬於程式的正常行為。

  • 應對需求變化的靈活性

    • 多端快速擴充套件的設計

      前端的使用者輸入採用了unity的InputSystem,可以將不同平臺的輸入處理為相同的方式來進行前端的操作。這意味著我們可以輕鬆地將前端部署在多個平臺上,如PC、手機、VR裝置、AR模式等,在不同的平臺我們只需要新增InputSystem的操作對映,無需對前端的其他地方更改。若後續需要在其他平臺部署,我們可以迅速地完成部署需求。

    • 前後端分離的模式

      前端嚴格按照多個場景分離設計,每一個場景是獨立執行的,有新的需求直接在相應的場景中進行修改即可,不會對其他場景造成影響。

    • 團隊協作原則

      我們採用coding平臺的團隊協作進行開發,每一個需求都指定到具體的人上,詳細的描述需求,另外也可釋出缺陷、任務等,可在碰到技術問題時艾特其他人共同解決,靈活協商。

2.1.3 測試設計

①單元測試

前端單元測試

Unity 測試框架包(Unity Test Framework,UTF)是一款工具,可在“編輯模式”和“播放模式”下以及在目標平臺(如獨立平臺、Android 或 iOS)上測試程式碼。

常規 NUnit 測試(在“編輯模式”和“播放模式”下執行):

[Test]
public void GameObject_CreatedWithGiven_WillHaveTheName()
{
    var go = new GameObject("UMetaObject");
    Assert.AreEqual("UMetaObject", go.name);
}

“播放模式”下的示例:

[UnityTest]
public IEnumerator GameObject_WithRigidBody_WillBeAffectedByPhysics()
{
    var go = new GameObject();
    go.AddComponent<Rigidbody>();
    var originalPosition = go.transform.position.y;

    yield return new WaitForFixedUpdate();

    Assert.AreNotEqual(originalPosition, go.transform.position.y);
}

“編輯模式”下的示例:

[UnityTest]
public IEnumerator EditorUtility_WhenExecuted_ReturnsSuccess()
{
    var utility = RunEditorUtilityInTheBackgroud();
    while (utility.isRunning)
    {
        yield return null;
    }
    Assert.IsTrue(utility.isSuccess);
}

通過 Test Runner API 從任何指令碼以程式設計方式執行測試。可以檢索將在“編輯模式”、“播放模式”或同時在這兩種模式下執行的測試的列表(不執行它們)。可以在每個測試的開始和結束、測試周期(即整個測試程式集)中的每個級別、每個單獨的測試固定例程以及每個測試類和測試上掛接一些註冊/取消註冊回撥。

在每個測試開始時,可以獲得有關將要執行的測試路線的資訊。測試完成後,可以看到測試結果。

除了在 Unity Editor 中以“播放模式”執行 UTF 之外,還可以使用新的自定義點在目標裝置上執行它。這是在構建 Player 之前呼叫的;可以修改 Player 構建選項,例如,更改測試執行設定和指定構建位置。

void Execute(ExecutionSettings executionSettings);
void RegisterCallbacks<T>(T testCallbacks, int priority = 0) where T : ICallbacks;
void UnregisterCallbacks<T>(T testCallbacks) where T : ICallbacks;
void RetrieveTestList(TestMode testMode, Action<ITestAdaptor> callback);
後端單元測試

SpringBoot 測試支援由兩個模組提供:

  • spring-boot-test 包含核心專案
  • spring-boot-test-autoconfigure 支援測試的自動配置

通常我們只要引入 spring-boot-starter-test 依賴就行,它包含了一些常用的模組 Junit、Spring Test、AssertJ、Hamcrest、Mockito 等。

下面是一個基本的單元測試例子,對某個方法的返回結果進行斷言:

@Service
public class UserService {
    public String getName() {
        return "UMeta";
    }
}
@RunWith(SpringRunner.class)
@SpringBootTest
public class UserServiceTest {
    @Autowired
    private UserService service;

    @Test
    public void getName() {
        String name = service.getName();
        assertThat(name, is("UMeta"));
    }
}
Controller 測試

Spring 提供了 MockMVC 用於支援 RESTful 風格的 Spring MVC 測試,使用 MockMvcBuilder 來構造 MockMvc 例項。MockMvc 有兩個實現:

  • StandaloneMockMvcBuilder:指定 WebApplicationContext,它將會從該上下文獲取相應的控制器並得到相應的 MockMvc

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class UserControllerTest  {
        @Autowired
        private WebApplicationContext webApplicationContext;
        private MockMvc mockMvc;
        @Before
        public void setUp() throws Exception {
            mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }
    
  • DefaultMockMvcBuilder:通過引數指定一組控制器,這樣就不需要從上下文獲取了

    @RunWith(SpringRunner.class)
    public class UserControllerTest  {
        private MockMvc mockMvc;
        @Before
        public void setUp() throws Exception {
            mockMvc = MockMvcBuilders.standaloneSetup(new UserController()).build();
        }
    }
    

下面是一個簡單的用例,對 UserController/v1/users/{id} 介面進行測試。

@RestController
@RequestMapping("v1/users")
public class UserController {
    @GetMapping("/{id}")
    public User get(@PathVariable("id") String id) {
        return new User(1, "UMeta");
    }

    @Data
    @AllArgsConstructor
    public class User {
        private Integer id;
        private String name;
    }
}
import static org.hamcrest.Matchers.containsString;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@RunWith(SpringRunner.class)
@SpringBootTest
public class UserControllerTest {
    @Autowired
    private WebApplicationContext webApplicationContext;
    private MockMvc mockMvc;

    @Before
    public void setUp() {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }

    @Test
    public void getUser() {
        mockMvc.perform(get("/v1/users/1")
                .accept(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(status().isOk())
           .andExpect(content().string(containsString("\"name\":\"UMeta\"")));
    }
}
Mock 資料

在單元測試中,Service 層的呼叫往往涉及到對資料庫、中介軟體等外部依賴。而在單元測試 AIR 原則中,單元測試應該是可以重複執行的,不應受到外界環境的影響的。此時我們可以通過 Mock 一個實現來處理這種情況。

如果不需要對靜態方法,私有方法等特殊進行驗證測試,則僅僅使用 SpringBoot 自帶的 Mockito 即可完成相關的測試資料 Mock。若需要則可以使用 PowerMock,簡單實用,結合 Spring 可以使用註解注入。

例如下面程式碼中,ProjectService 中通過 ProjectMapperselectById 方法進行資料庫查詢操作:

@Service
public class ProjectService {
    @Autowired
    private ProjectMapper mapper;

    public ProjectDO detail(String id) {
        return mapper.selectById(id);
    }
}

此時我們可以對 Mock 一個 ProjectMapper 物件替換掉 IOC 容器中原生的 Bean,來模擬資料庫查詢操作,如:

@RunWith(SpringRunner.class)
@SpringBootTest
public class ProjectServiceTest {
    @MockBean
    private ProjectMapper mapper;
    @Autowired
    private ProjectService service;

    @Test
    public void detail() {
        ProjectDemoDO model = new ProjectDemoDO();
        model.setId("1");
        model.setName("umeta-demo");
        Mockito.when(mapper.selectById("1")).thenReturn(model);
        ProjectDemoDO entity = service.detail("1");
        assertThat(entity.getName(), containsString("umeta-demo"));
    }
}

②壓力測試

  • 測試內容
    • Java 伺服器暫定支援 1000 級別的併發,因此針對訪問較為頻繁的幾個頁面進行壓力測試,檢視效能是否符合要求。
  • 測試場景設定
    • 對於邏輯簡單的部分,使用使用效能測試工具,如 ApacheBenchmark ab 進行併發數為 1000 的測試;
    • 對於邏輯複雜的部分,在 SpringBoot 內部編寫相關測試函式進行測試。
  • 伺服器狀態監視
    • 使用 htop 工具監視伺服器的 CPU、記憶體使用情況並記錄資料。
  • 測試結果收集與分析
    • 由於產品後端部署環境有很多引數可以調節,例如,MySQL可以配置max_connectionsthread_cache_sizeback_log等引數,因此,我們可以收集設定不同引數下系統的狀態資訊與當前併發數,構造關係表格進行分析,理想情況下應該能找出併發瓶頸。

③真實測試

真實測試是對我們的系統進行一系列實際使用時會遇到的真實情況的模擬。我們團隊將從以下方面對真實的情況進行分類並進行測試

  • 功能測試
    • 手動測試,模擬真實使用者進行功能實現與否的測試
    • 自動化測試,設計測試用例,實際上就是針對程式碼的單元測試
  • 專項測試
    • 相容性測試,使用不同裝置,不同型號,不同解析度對使用者介面進行測試
    • 安裝解除安裝升級測試
    • 交叉事件測試,包含執行時接收來電/簡訊/訊息推送、執行時出現系統彈窗、執行時切換外部裝置等
    • 使用者體驗度測試,包含介面設計、功能易用性、橫豎屏切換、系統功能響應等
    • 穩定性測試通過測試工具實現在一定時間範圍內的無序操作,來檢測應用的穩定執行能力,重點在於考察應用在測試期間出現程式無響應或閃退的頻率
  • 安全測試
    • 對異常邏輯、hack 介面、網路攻擊防禦等情況進行測試,系統不得有安全漏洞或隱患
  • 效能測試
    • 客戶端:包含 CPU/記憶體佔用、介面流暢度、流量/電量消耗、啟動時間等
    • 服務端:使用效能測試工具,如 ApacheBenchmark ab

2.1.4 效能分析

“靈境”致力於小場景社交服務、校園場景社交服務以及高校社交,使用者可進行本校社交、跨校社交、個人空間裝飾以及相互訪問等活動,在使用過程中可能面臨大量使用者同時登陸使用的情況,存在高併發情形。

前後端分離,客戶端主要提供使用者瀏覽的頁面,基於C#的Unity框架及其內建各種功能外掛進行安卓客戶端設計,後端分為分為遊戲後端和資料後端,採用SpringBoot+Mybatis-Plus以及Websocket+Netty,其中游戲後端負責實現多人同步問題,資料後端進行資料管理。

快速的錯誤處理,當客戶端、遊戲後端和資料後端發生錯誤時,能及時收集相關錯誤資料,進行分析並快速做出應對措施,以保證使用者良好的體驗。

2.2 業務流程層面

2.2.1 前端

注:基本的輸入格式表單驗證不包括在下表中

功能模組 輸入假設 錯誤處理
登入 賬號存在 根據後端介面異常顯示錯誤提示
註冊 賬號未註冊;手機號有效 根據後端/驗證碼API的異常顯示錯誤提示
我的高校 已註冊賬號並認證高校 引導使用者進行認證
高校場景 伺服器能夠承載 提示伺服器過忙,請使用者重新選擇伺服器
高校場景
我的空間
使用者全屏顯示 元件橫屏豎屏適配

2.2.2 後端

問題 輸入假設 錯誤處理
寫操作異常輸入 前端所有輸入經過格式和有效性檢查 不儲存資料,丟擲異常
刪/查操作 刪除/查詢對應的物件存在 返回空值,必要時丟擲異常
增加重複 註冊賬號不存在 丟擲重複註冊賬號異常
資源缺失 需要載入的人物、場景等建模存在 丟擲資源缺失異常
伺服器過載 使用者數未超過上限 不分配資源,丟擲異常

Part3 更新日誌

時間 更新內容
2022-04-19 18:00 按照班級作業要求完成技術規格說明書