uoj專案部署的學習實踐和基於JUnit進行的專案測試

ighshssjjsjs發表於2024-05-30

基於JUnit進行的專案測試

對不同功能點進行測試:
檢測忘記密碼功能、註冊功能能否正常使用
指令碼檔案:registerTest.java

1.檢測忘記密碼功能。事先註冊好一個賬號用於測試
測試步驟:輸入賬號
輸入電子郵箱
輸入驗證碼

1)用例標題:驗證碼錯誤情況
測試資料:賬號 2021127
電子郵箱 2848250875@qq.com
驗證碼 1234
預期結果:驗證碼錯誤
實際結果:Verify Code Wrong!

2)用例標題:驗證碼正確情況
(由於驗證碼會變化,這裡手動輸入驗證碼來完成正確的填寫)
測試資料:賬號 2021127
電子郵箱 2848250875@qq.com
驗證碼 (手動填寫)
預期結果:進入忘記密碼下一級操作
實際結果:向郵箱傳送驗證資訊

2.檢測註冊功能
測試步驟:輸入使用者名稱
輸入暱稱
輸入密碼
重複輸入密碼
輸入學校(可選)
輸入郵箱

1)用例標題:使用者名稱重複情況
測試資料:使用者名稱 2021127
暱稱 clkr
密碼 123456
重複密碼 123456
郵箱 2848250875@qq.com
預期結果:使用者存在無法註冊
實際結果:

2)用例標題:正常註冊情況

測試資料:使用者名稱 2021008
暱稱 cll
密碼 123456
重複密碼 123456
郵箱 2848250875@qq.com
預期結果:成功註冊並登入
實際結果:成功註冊並登入

登入功能測試
指令碼檔案:loginTest1.java
分出正確賬號密碼,不正確賬號正確密碼,正確賬號不正確密碼,全部不正確賬號密碼四種用例測試。
錯誤輸入包括缺位,錯誤輸入,多輸入,大小寫錯誤,空格輸入
用例舉例如下
正確:


錯誤輸入:



不正確賬號正確密碼,正確賬號不正確密碼,全部不正確賬號密碼無法登入
輸入出現缺位,錯誤輸入,多輸入錯誤,密碼大小寫,密碼空格錯誤無法登入。

測試介面穩定:
指令碼檔案:Test1.java

透過測試長時間處於同一頁面是否會造成卡頓
開啟頁面並進行休眠

uoj專案部署中題目管理的相關學習
一.概述
1.新建題目和管理介面

只有超級管理員有許可權新建題目,每次新建題目都必須由超級管理員完成。
在題目頁面,超級管理員或該題目的管理員可以透過管理按鈕進入題目管理介面。題目管理介面分為三個選項卡:
編輯:題面編輯頁面
管理者:題目管理員管理頁面
資料:題目資料管理頁面
以及用來退出題目管理介面的返回按鈕。

2.編輯題面
UOJ 的題面使用 Markdown 編寫。

理論上,題面是可以自由編寫的,但還是有一些推薦的格式和規則:

中文與英文、數字之間加一個空格隔開。
輸入輸出樣例視為程式碼塊,使用Markdown的 ``` 語法。
題面中最高階標題為三級標題。
一切數字、數學符號、運算子、變數名、公式應當用 LaTeX 語法編寫。UOJ 自帶 MathJax 外掛來顯示數學公式,行中公式用$ $分隔,獨立公式用$$ $$分隔。

3.編輯標籤
直接填入文字框即可,用英文半形逗號分隔多個標籤。

理論上,標籤是可以自由標定的,但還是有一些推薦的規則:

標籤的目的是標出題目型別,方便使用者檢索題目。一般來說,標籤順序基本為從小範圍到大範圍。
最前面的幾個標籤是這題所需要的前置技能,這裡假定 “二分查詢” 之類過於基礎的技能選手已經掌握。
接下來是這道題的大方法,比如 “貪心”、“DP”、“亂搞”、“構造”、“分治”……
接下來,如果這道題是非傳統題,用一個標籤註明非傳統題型別,比如 “提交答案”、“互動式”、“通訊”。
接下來,如果這道題是模板題,用一個標籤註明 “模板題”。
接下來,如果這道題是不用腦子想就能做出的題,例如 NOIP 第一題難度,用一個標籤註明 “水題”。
最後,如果這題的來源比較重要,用一個標籤註明。比如 “UOJ Round”、“NOI”、“WC”。
前置技能中,“數學” 太過寬泛不能作為標籤,但 “數論” 可以作為前置技能。
如果有多個解法,每個解法的前置技能和大方法都不太一樣,那麼儘可能都標上去。
“亂搞” 標籤不宜濫用。
請注意,如果您加入了“模板題”這一標籤,這道題目便會進入模板題庫。這一特性不能推廣。

4.zip 資料包上傳
這裡上傳時要打包為一個資料包,例如:

二.傳統題配置
1.資料
對於傳統題,上傳的×.zip資料包應當包括這些內容:

題目配置檔案
測試資料
額外測試資料(包括題面中所給的測試樣例)
(開啟 hack)資料檢驗器
(開啟 hack)標準程式

2.題目配置檔案
題目配置檔案應當命名為problem.conf。這是一份配置的樣例:

  • [n_tests 10
    n_ex_tests 1
    n_sample_tests 1
    input_pre www
    input_suf in
    output_pre www
    output_suf out
    time_limit 1
    memory_limit 512
    output_limit 64
    use_builtin_judger on
    use_builtin_checker ncmp ]

測試點

  • [ n_tests 10
    n_ex_tests 1
    n_sample_tests 1]

這三行分別代表標準測試點、額外測試點和測試樣例的數量。其中,額外測試點的前幾個一定是測試樣例,所以你必須把題目中給出的測試樣例放到額外測試點當中。

UOJ 的 extra test 是指在 AC 的情況下會測額外資料,如果某個額外資料通不過會被倒扣3分。

  • [input_pre www
    input_suf in
    output_pre www
    output_suf out ]

這四行分別指明瞭每個測試點輸入檔案的字首、副檔名、輸出檔案的字首、副檔名。

標準測試點的檔名應當形如:www1.in、www1.out、www2.in、www2.out……

額外測試點的檔名應當形如:ex_www1.in、ex_www1.out、ex_www2.in、ex_www2.out……

限制
time_limit 1
memory_limit 512
output_limit 64
這三行配置了評測時對選手程式的時間限制、記憶體空間限制和輸出限制。

時間限制的單位為秒,不能為小數。記憶體空間和輸出限制的單位為 MB。

校驗器(checker)
校驗器用來檢查選手程式的輸出是否正確。

use_builtin_judger on
use_builtin_checker ncmp
第一行表示使用內建校驗器,第二行表示使用的校驗器型別。testlib 提供了很多奇奇怪怪的校驗器。

三.特殊需求配置
由於很多題目有亂七八糟的配置,uoj用了一些不清真的方法來實現。

1.子任務
子任務模式中,必須把某個subtest的資料全部透過才能拿到對應的分數。

在problem.conf中,可以設定每個子任務在哪個測試點結束,並給每個子任務分配對應的分數。

它的寫法如下:

  • [ n_tests 40

...

n_subtasks 6
subtask_end_1 5
subtask_score_1 10
subtask_end_2 10
subtask_score_2 10
subtask_end_3 15
subtask_score_3 10
subtask_end_4 20
subtask_score_4 20
subtask_end_5 25
subtask_score_5 20
subtask_end_6 40
subtask_score_6 30]

每個測試點不同分值
如果需要對每個測試點給不同的分數,可以在problem.conf中用point_score_x實現。

它的寫法如下:

  • [n_tests 7

...

point_score_1 5
point_score_2 10
point_score_3 15
point_score_4 30
point_score_5 10
point_score_6 15
point_score_7 15 ]

2.ACM模式
ACM模式的題目,如果錯掉任何一個測試點就不得分。

可以透過將所有的資料都放進一個subtask來實現。

四.資料檢驗器
uoj的資料檢驗器(val.cpp)使用testlib。

下面是A+B Problem的檢驗器:

 #include "testlib.h"
 using namespace std;

 int main(void)
 {
    registerValidation();

inf.readInt(0,1000000000,"A");
inf.readSpace();
inf.readInt(0,1000000000,"B");
inf.readEoln();

inf.readEof();
return 0;
}

上面的程式碼是這樣工作的:

registerValidation():初始化。
inf.readInt(0,1000000000,"A"):讀入叫做“A”的整形變數,範圍必須在[0,1000000000]以內。如果不滿足要求,則判定資料無效。
inf.readSpace():讀取一個空格。
inf.readEoln():讀取一個換行符。
inf.readEof():讀取檔案結束符。
上面的讀取中,只要有任意一個出現了偏差,則判定資料無效。

如果資料需要保證某個要求,可以使用ensuref():

ensuref(cmd=='Q' || cmd=='A' || cmd=='C' , "您輸入的操作不合法");

在上面的程式碼中,如果cmd既不是'Q',也不是'A'或'C',則判定資料無效,並提示您輸入的操作不合法。

五.答案檢查器
本文將引導您寫一個自定義的checker(chk.cpp)。
按照套路,uoj的校驗器也應該使用testlib編寫。
下面是A+B Problem的校驗器:

#include "testlib.h"

int main(int argc, char* argv[])
{
registerTestlibCmd(argc, argv);

int pans,jans;
pans=ouf.readInt();      // 讀取選手輸出
jans=ans.readInt();      // 讀取答案

if (pans == jans)
    quitf(_ok, "Correct.");
else
    quitf(_wa, "WA! expect=%d recieve=%d", jans, pans);
}

在呼叫registerTestlibCmd之後,我們可以使用下面的三個流:

inf : 輸入資料
ouf : 選手輸出
ans : 標準輸出
從流中讀取資料的方式,和【資料檢驗器】一致。

如果程式AC或者爆零,可以使用quitf()。但是如果想給選手部分分,使用下面的程式碼:

quitp(ceil(100.0 * p / a) / 100, "QAQ");

uoj概述

一、基本工作原理
UOJ 主要由兩部分組成:網頁端和測評端。顧名思義,網頁端就是用來透過網頁與使用者互動的,測評端則是在使用者發出測評請求時負責測評並將結果傳送給網頁端的。

  1. 網頁端
    什麼是網頁端?顧名思義,就是管網頁的部分。網頁端又分為網頁前端和網頁後端。所謂網頁前端,就是你開啟瀏覽器能看到的那部分。不過瀏覽器是如何知道自己要顯示什麼東西的呢?這就是因為伺服器上還有網頁後端,會以 HTML 程式碼的形式告訴瀏覽器它要顯示些什麼。

下面我們來理一下你從輸入網址到看到網頁的全過程。首先,你輸入了 UOJ 的網址,然後瀏覽器就會根據你的網址去找到對應的伺服器,併發一個訊息給該伺服器。這種訊息稱為 HTTP 請求(HTTP Request)。當然了,這取決於你的網址是以什麼開頭的。如果是 https 開頭那麼就是個加了密的 HTTP 請求,稱為 HTTPS 請求。一個 HTTP 請求報文會包含很多很多資訊,例如你輸入的網址啦,例如你的 IP 啦。

伺服器收到 HTTP 請求之後,會根據請求的內容進行相應的處理,並生成一個 HTTP 響應(HTTP Response),然後發回給你的瀏覽器。HTTP 響應報文也會包括很多資訊。比如會包括狀態碼,正常情況下是 200,但如果對應的網址上沒有東西可顯示,那麼會返回一個喜聞樂見的 404。當然最重要的是 HTTP 響應報文裡面會包含一份 HTML 程式碼,這份程式碼會指示你的瀏覽器如何渲染出一個完整的網頁。只要你在瀏覽器裡滑鼠右鍵,點選審查元素,就能看到這份 HTML 程式碼了。實際上,HTML 程式碼中可能還會內嵌有其他的元素,例如內嵌一些 JavaScript 程式碼就可以做一些動態的頁面效果,內嵌一些 CSS 程式碼就可以更好的控制網頁的排版。

總而言之,想要理解網頁端,就得理解兩部分:第一,瀏覽器是如何把 HTML 程式碼變成你所看到的網頁的;第二,伺服器是如何根據 HTTP 請求報文生成 HTML 程式碼的。前者屬於網頁前端的範疇,而後者屬於網頁後端的範疇。

  1. 測評端
    光有網頁端是不夠的,因為如果使用者提交了一份程式碼,UOJ 就得負責評測,而這往往不是幾秒鐘內能完成的,所以不能用 HTTP 響應的方式快速返回結果。因此,UOJ 的網頁端伺服器得把該測評請求發給另一個被我們稱之為測評端的伺服器,讓它測評之後將測評結果發回,再透過網頁端告知使用者。

UOJ 官網的網頁端和測評端伺服器是分別部署在兩臺機器上的,不過為了方便起見,在我們釋出的這版 UOJ 裡網頁端和測評端是放在同一臺機器上的。

測評端又分為負責通訊的部分和(真正)負責測評的部分。顧名思義,負責通訊的程式碼控制的是和網頁端伺服器的互動,而負責測評的程式碼則是給選手交過來的檔案打分的,最後負責通訊的部分會將測評結果發回網頁端。

二、網頁端程式碼簡介
下面我們稍微展開講一講 UOJ 網頁前端和網頁後端分別是如何實現的。

  1. 網頁後端
    UOJ 使用了一款開源的網頁伺服器軟體,叫作 Apache。Apache 支援使用 PHP 語言來實現網頁後端。進入 UOJ 的 docker,網頁後端的程式碼就位於 /opt/uoj/web/ 目錄下。Apache 收到一個 HTTP 請求之後,會執行 index.php(這一行為其實是由同目錄下的 .htaccess 指定的)。index.php 會載入所需的函式庫和類庫,然後根據路由檔案(route file) 去給請求中的網址匹配用於生成響應報文的 PHP 程式碼。所謂路由檔案其實也是 PHP 程式碼,只不過這種檔案記錄了一個從網址到程式碼檔案路徑的對映。控制主站路由的是 app/route.php,控制部落格路由的是 app/controllers/subdomain/blog/route.php。

我們稱路由檔案中被對映到的程式碼為控制器(controller),位於 app/controllers 目錄下。index.php 給請求中的網址匹配到對應的控制器後,控制器會根據使用者的 HTTP 請求報文的具體內容生成一個 HTTP 響應報文,交由 Apache 負責發回給作出 HTTP 請求的瀏覽器。

早期 UOJ 的網頁後端是我們一點一點自己寫的,架構上沒有參考任何的現有開源專案。後來我們發現有些架構的設計思路理不太清楚,於是去學習了一下著名的 Laravel 框架。所以程式碼架構實則是介於早期 UOJ 架構和 Laravel 之間的一種架構,沒有像早期架構那麼亂,也沒用像專業的 Laravel 那樣包裝得很深,希望這樣能兼顧程式碼的可維護性和可閱讀性吧。

  1. 資料庫
    資料庫是網頁後端的一部分,但又是較為獨立的一部分。通常我們在 OI 中會使用陣列來儲存資料,但一旦你把程式掐了,或者電腦關機了,陣列裡的內容就丟失了。這是因為陣列通常是儲存在記憶體裡的,而非機械硬碟、固態硬碟等可持久儲存的介質上。那麼如何把資料儲存在硬碟上呢?你可能已經開始摩拳擦掌準備寫個 B 樹了,但是且慢 —— 如今有很多資料庫軟體已經幫你寫好了。

UOJ 使用的是 MySQL 資料庫。在 UOJ 的後端 PHP 程式碼裡,你可以透過訪問 DB 這個靜態類來跟資料庫進行互動。互動使用的是 SQL 語言,一種專門為資料庫中資料的查詢、修改、插入、刪除而設計的語言,你可能需要稍微學習一番這種特殊的語言。DB 是對 SQL 的一種簡單包裝,請參照現有程式碼呼叫 DB 的方式來更好的理解其用法。

  1. 網頁前端
    大部分的網頁前端程式碼實際上是由 PHP 一行一行輸出出來的。負責這種輸出的程式碼一部分位於各個控制器程式碼中,一部分 app/views 目錄下。理想情況下,如果一段 PHP 程式碼能生成一長段 HTML 程式碼,且生成的過程不包含任何控制邏輯或者資料庫查詢,那麼該 PHP 程式碼就應該放在 app/views 裡作為一種檢視(view);否則就應該放在 app/controllers 下作為一種控制器。例如,每個頁面都會包含的頁頭和頁尾就寫在了 app/views/page-header.php 和 app/views/page-footer.php 這兩個檢視檔案裡。當然了,嚴格遵守這樣的規則會讓一些簡單的程式碼變得結構很複雜,所以目前的 UOJ 程式碼並沒有嚴格遵守這一點。

其實,並非所有前端程式碼都是 PHP 一行行輸出出來的。HTML 程式碼中通常會內嵌一些 CSS 和 JavaScript 來控制頁面排版和製造一些動態頁面效果,而這些部分往往是跟頁面具體內容獨立的。所以有很多優秀的前端框架,例如 Bootstrap。UOJ 目前使用的是 Bootstrap 3。所以,要想完全理解前端的程式碼,你不僅需要閱讀對應的控制器和檢視的內容,還要學習一下 Bootstrap 的使用方式。如果你尚未接觸過前端開發,不妨先找點前端開發教程,試著做一點不需要 PHP 的靜態小網站,然後再回過頭來閱讀 UOJ 的程式碼。

  1. 重要檔案目錄
    網頁端的程式碼和相關檔案主要在 /opt/uoj/web/ 目錄下。下面列出了一些重要的檔案和子目錄:

app/:UOJ 主要的後端 PHP 程式碼目錄
controllers/:存放控制器檔案的目錄
locale/:存放頁面上的文字在不同語言下的翻譯的目錄
models/:UOJ 執行所需的一些 PHP 類
storage/:儲存一些檔案資料的目錄
submissions/:存放使用者提交的測評請求中附帶的檔案的目錄
tmp/:存放臨時檔案的目錄
views/:存放檢視檔案的目錄
route.php:主站路由檔案
uoj-*-lib.php:一些 UOJ 執行所需的函式庫檔案
vendor/:一些 UOJ 使用的第三方 PHP 程式碼庫,由 Composer 管理。
public/:一些可以不經過 PHP 直接訪問的資源
css/:存放部分 CSS 程式碼檔案的目錄
fonts/:存放字型檔案的目錄
js/:存放部分 JavaScript 程式碼檔案的目錄
libs/:一些 UOJ 使用的前端庫,例如 Bootstrap,jQuery 等等
pictures/:存放部分圖片檔案的目錄

相關文章