全文共2455
字,推薦閱讀時間10~15
分鍾。
文章共分四個部分:
自動化測試
這一部分不對自動化測試的普適定義做過多探討,即文章不展開所有的命令行的使用和函數調用。主要聚焦於本單元評測機的評判機制和具體實現。
話不多說,下面正式開始介紹一種可能的評測機實現方式。
文檔結構

center
:存放評測的核心控制代碼,用於組織編譯->運行->反饋
功能data
:存放自動生成的數據download_data
:存放測試中出現問題的數據,可以用於回歸測試。factory
:存放數據生成代碼lib
:存放JAR
包output
:存放各個測試代碼的輸出result
:存放各個測試代碼的結果ruler
:存放標程或評測邏輯(即spj
的邏輯判斷代碼)server
:用於適配服務器端的調用代碼summary
:用於存放反饋整合后的結果(在調優部分會提及)
評判邏輯
根據指導書的提示和合理外推,可以歸納出以下不少的判斷規則:
-
A:
電梯載客時電梯內人數不能超出電梯容量6人
相鄰arrive的間隔大於等於0.4s
只能在-3 -2 -1 1 15~20樓層停靠 -
B:
電梯載客時電梯內人數不能超出電梯容量8人
相鄰arrive的間隔大於等於0.5s
只能在-2 -1 1 2 4~15樓層停靠 -
C:
電梯載客時電梯內人數不能超出電梯容量7人
相鄰arrive的間隔大於等於0.6s
只能在1 3 5 7 9 11 13 15樓層停靠 -
電梯每次移動距離為1(Arrive是連續的,不允許出現跳躍)
-
電梯不能到達無法到達的樓層
-
電梯開門時門必須是關閉狀態
-
電梯停下后才可以在對應樓層開門
-
電梯關門時門必須是打開狀態
-
電梯關門后才可以繼續移動
-
電梯開關門速度不能超出限制
-
一對開關的樓層必須相同
-
程序結束后所有電梯門必須為關閉狀態
-
電梯裝卸乘客時門必須是開啟狀態
-
電梯裝卸乘客時乘客必須在當前樓層等待
-
電梯載客時乘客必須在門外
-
電梯卸客時乘客必須在電梯上
-
程序結束后所有乘客必須抵達目的地
-
被拆解的請求要檢查每一個分請求是否得到滿足
重要節點的實現
運行評測代碼
在上個單元中,每次互測時為了能夠使用命令行直接編譯出可運行的.class
文件,評測機采用的都是即刻編譯、即刻運行的工作邏輯。但是有感於大家的創造力,(每個人的主類命名都不一樣,再來個便想到了調用package
的話,就更棒了)JAR
包的方法——這是真正意義上的“黑箱”測試,因為不需要為了命令行的參數修改任何一份代碼的主類。
關於JAR
的生成,可以參考網上的教程,win
和linux
端都有。
生成好之后,就可以統一運行所有的代碼了。
java -jar xxx.jar
這命令行有沒有很熟悉?
計組的Mars
不就是這樣用的嗎
評判邏輯的實現
這一部分其實就是讀文檔+if
判斷,大家都知道,就不贅述了。
多線程評測
既然在學Java多線程,那為什么不順手用用Python多線程呢?(雖然沒有因果關系)
subprocess()
模塊就是Python
最親民的一種啟動多線程方式,其他類似Java的創建特殊類的辦法在這里並沒有用武之地,殺雞焉用牛刀,最適合的才是最好的。
from subprocess import Popen
elev_proc = Popen(r'java -jar xxx.jar',
stdin=PIPE,
stdout=f_out,
stderr=f_out,
shell=True
)
注意到參數列表中的stdin
,stdout
,stderr
其實是在重定向線程的輸出流,便於后期的分析。最后的shell=True
是為了適配Linux
加上的,這里在調優部分會體現出來。
其他
關於flush
等評論區已經有討論結果的操作,就不在此詳述了。
正確性評測結果展示

可以類似中斷機制一樣建立一個中斷向量表,發現問題直接中斷評測程序,根據中斷號返回相應的原因。這對黑盒測試后的修正工作是有非常大的幫助的。
調優策略
首先,請允許我對直接用線性規划等其他數學工具推導最優解的朋友致以崇高的敬意。
但是
重要的事說三遍:
這一部分沒有理論推導!
這一部分沒有理論推導!
這一部分沒有理論推導!
為什么呢?
因為找到的最優策略不是算出來的,是進化出來的。
“在數學的天地里,重要的不是我們知道什么,而是我們怎么知道什么.” ——畢達哥拉斯
最吸引我們的當然是這最優解到底是什么,但是,“怎么知道它”在不知道它之前比它到底是什么更加重要。(告訴我你沒有沒繞暈)
能讓計算機的計算功能為我們所用的時候請千萬不要吝嗇,因為面前的i7可以匹敵幾千萬個你的計算速度。
先給大家展示最后用於分析的可視化結果(出於博客的觀看體驗考慮,只展示四種調度算法的結果)
-
運行時間走勢
-
在所有數據里取得最優解的次數
-
平均調度時間及其方差和標准差
(標准差在該情境下和方差等價)
我們可以很直觀的得出結論:
- 在這四種算法中,第三種的均值是最優的,方差也能夠讓人接受。
相比於在一堆.txt
文件里頭腦排序,是不是效率會高一點點呢?更重要的是,總不能心算方差吧?(如果能也請當我沒說)
現在的情境下只有4種算法,所以優勢體現的並不是很明顯。但是我們可以試想以下情景:
- 在第三次作業中,要求我們加入電梯時,我們是全都放在一層嗎?還是說有更好的調度策略?
粗略估計一下,假設加入1台A,那么兩台A的分配大約會多出100種樓層安排方式,那要是3台呢?(歡迎繼續心算)但是如果我們利用可視化的工具,就算是再多10台,給我一塊N卡,給我三天時間,一定能找到已知范圍內的相對最優解。
總結一下,相對於數學方法,這樣會顯得很沒有技術含量,但是,這種問題很可能是NP的。(如果有同學已經證明了,請教教我怎么證)所以,三天時間對數學的要求可能有點點高。
但是它也有一定的短板,就是樣本容量要足夠的大,以及參與比較的調度算法不能都處於較低的性能水平,要不就變成了“矮子里充高子”了。
找到相對最優解之后的點對點優化大家都很明白,就不在此班門弄斧了。
CPU時間測定
接下來,我們要在本地自動化測試CPU時間(啥玩意兒?)
在和大家的交流以及經過了學長的指點后,發現這個問題對win
用戶確實很不友好——在linux
下使用time
系統調用可以輕松地實現上述操作。
但是,我們有萬能的python
——在time
庫中有一個神奇的函數process_time()
,根據官方文檔是可以實現和前者一樣的功能的。
但是,由於這個函數的subprocess
的兼容性並不好,最后還是選擇了前者。(I am so into Linux)
以下提供一種可能的參考實現
''' evaluate time on Linux '''
r = Popen("time python ./server/get_output.py " + self.dirname + " " +
self.datadir,
stderr=PIPE,
shell=True)
s = str(r.stderr.read()).replace('\'', '')[1:]
usr_time = float(s.split(' ')[0][:-4])
sys_time = float(s.split(' ')[1][:-6])
cpu_time = sys_time + usr_time
self.check_result(cpu_time)
# print(usr_time)
# print(sys_time)
需要注意的是,
time
命令直接在terminal
中調用和使用os.system
調用的返回結果是不一樣的。因此,得到的結果也需要不同的處理方式,具體就看大家喜歡哪一種了。
CPU時間測試展示

注意到上一張圖中
CPU TIME
是0,因為那是在win
下的結果,沒有實現time_check()
.
結語
測試是門大學問,OO是門好課程。
我愛OO!