jmeter壓力測試簡單使用
結對專案
軟體工程 | 班級網址 |
---|---|
作業要求 | 作業要求程式碼 |
作業目標 | 積累結對專案經驗,提高交流和合作能力 |
合作者
黃博曉 資訊保安 (1) 班 學號 : 3118005363
凌文宇 資訊保安 (1) 班 學號 : 3118005372
作業程式碼連結
github 網址 : https://github.com/bxxiao/bxxiao/tree/master/ArithmeticGeneratorProject
PSP 表格
PSP2.1 | Personal Software Process Stages | 預估耗時(分鐘) | 實際耗時(分鐘) |
---|---|---|---|
Planning | 計劃 | 30 | 40 |
· Estimate | · 估計這個任務需要多少時間 | 30 | 40 |
Development | 開發 | 740 | 790 |
· Analysis | · 需求分析 (包括學習新技術) | 200 | 150 |
· Design Spec | · 生成設計文件 | 50 | 40 |
· Design Review | · 設計複審 | 20 | 40 |
· Coding Standard | · 程式碼規範 (為目前的開發制定合適的規範) | 30 | 30 |
· Design | · 具體設計 | 40 | 60 |
· Coding | · 具體編碼 | 300 | 350 |
· Code Review | · 程式碼複審 | 40 | 50 |
· Test | · 測試(自我測試,修改程式碼,提交修改) | 60 | 70 |
Reporting | 報告 | 70 | 85 |
· Test Repor | · 測試報告 | 30 | 30 |
· Size Measurement | · 計算工作量 | 15 | 20 |
· Postmortem & Process Improvement Plan | · 事後總結, 並提出過程改進計劃 | 25 | 35 |
· 合計 | 840 | 915 |
1. 設計實現過程
包結構:
-
expression包:一個Expression物件表示一個四則表示式,其中提供了隨機建立表示式、檢驗表示式、獲取表示式運算結果和返回表示式字串形式等方法。一個四則表示式封裝為一個二叉樹,TreeNode是二叉樹的結點,每個結點儲存一個運算子或運算數。
-
util包:
-
Calculator:主要提供了針對整數、分數的加減乘除運算、以及獲取分數的最簡形式的靜態方法。運算結果以字串形式返回。返回形式有整數和分數(如1/3,2'5/6)形式。
-
Ran:用於生成隨機值。包括隨機生成運算子、隨機生成運算數(整數和分數)以及隨機生成運算子在二叉樹中的位置。
-
CommandResolver:命令解析器。解析main方法的args引數,獲取其中的有用引數。若輸入形式不符合要求,會列印提示資訊。若輸入形式符合要求,則獲取其中指定的題目數和最大值並儲存。
-
FilteUtil:用於將生成的題目跟答案寫入檔案。寫入的格式如下:
1. exp1 = or answer1 2. exp2 = or answer2 3. exp3 = or answer3 ...
-
-
generator包:
- Generator:提供了一個
generate()
方法,使用CommandResolver
解析輸入的命令,獲取題目數和最大值,根據這兩個值建立表示式和對應的答案,並使用FilteUtil
將題目和答案寫入當前目錄下的expFile.txt和answers.txt檔案(若不存在會建立)。在建立每個表示式之前,先隨機生成一個1-3的整數,作為運算子個數。 - Main:包含main方法。
- Generator:提供了一個
-
test包:包含一個測試類。(使用Junit)
2. 程式碼說明
2.1 表示式的字串形式
一個表示式對應的二叉樹是一個完全二叉樹,其中,葉子結點都是運算數,父結點都是運算子。對這樣的二叉樹進行中序遍歷可得到一個運算表示式,且每次返回父結點都會帶上括號,如:
遍歷結果是((1+2)-(3x4))
。
再通過以下原則去除多餘的括號
假設待去括號的表示式為
(m1 op1 n1) op (m2 op2 n2)
這裡m1、n1、m2、m2可能自身就是個表示式,也可能是數字,op、op1、op2為運算子1、若op為'÷',則 (m2 op2 n2)的括號必須保留;
2、若op為'x'或'-',如果op2為'+'或'-',則(m2 op2 n2)的括號必須保留;
3、若op為'x'或'÷',如果op1為'+'或'-',則(m1 op1 n1)的括號必須保留;
4、 除此之外,去掉括號不影響表示式的計算順序。
如上面例子去掉多餘括號後變為:1+2-3x4
將當前二叉樹按以上規則轉換為字串形式的方法在TreeNode中:
public String toString(){
String leftExp = "";//左表示式
String rightExp = "";//右表示式
String result = "";//運算子
//若當前結點有孩子
if(hasChild()){
//右子樹如果有孩子,說明右子樹是一個表示式,而不是數字節點。
if(getRchild().hasChild()){
//判斷左鄰括號的運算子是否為'/'
if(str.equals("÷")){
//獲取右子樹的表示式,保留括號
rightExp = getRchild().toString();
}
//判斷左鄰括號的運算子是否為'x'或'-'
else if(str.equals("x") || str.equals("-")){
//判斷op是否為'+'或'-'
if(getRchild().str.equals("+") || getRchild().str.equals("-")){
rightExp = getRchild().toString();
}
else{
//獲取右子樹的表示式,並且去括號
rightExp = getRchild().toString().substring(1, getRchild().toString().length()-1);
}
}
else{
//右子樹除此之外都是可以去括號的。
rightExp = getRchild().toString().substring(1, getRchild().toString().length()-1);
}
}
else{
rightExp = getRchild().str;
}
//左子樹的情況同右子樹類似
if(getLchild().hasChild()){
if(str.equals("x") || str.equals("÷")){
if(getLchild().str.equals("+") || getLchild().str.equals("-")){
leftExp = getLchild().toString();
}
else{
leftExp = getLchild().toString().substring(1, getLchild().toString().length()-1);
}
}
else{
leftExp = getLchild().toString().substring(1, getLchild().toString().length()-1);
}
}
else{
leftExp = getLchild().str;
}
//獲取當前的運算式,並加上括號
result = "(" + leftExp + " " + this.str + " " + rightExp + ")";
}
else{
//若沒有孩子,說明是數字節點,直接返回數字
result = this.str;
}
return result;
}
2.2 隨機生成表示式
2.2.1 隨機建立表示式
隨機生成二叉樹的思路:
- 先隨機生成一個運算子作為根結點。若只有一個運算子,直接生成兩個運算數作為根節點的左右孩子。
- 若有2或3個運算子:
- 先根據運算子個數隨機獲取運算子結點位置的boolean陣列(見下文
getChildPlace()
)。 - 遍歷該boolean陣列,若為true,則要建立一個表示式子樹(運算子為父結點,運算數為其左右孩子);若為false,則建立一個運算數子樹(只有一個結點)。
- 在上述遍歷中設定一個遍歷索引
i
,若i為偶數,則建立的子樹作為"當前結點"的左孩子,否則為右孩子。且每建立一個作為左孩子的表示式子樹,則該子樹的根節點作為“當前結點”(當前結點從第一步生成的根節點開始)... - 這種方式建立子樹能保證最後生成的二叉樹是完全二叉樹。
- 先根據運算子個數隨機獲取運算子結點位置的boolean陣列(見下文
- 建立完表示式,呼叫
CalAndVal()
對錶達式校驗。
public void createExpression(){
TreeNode lchild, rchild, lnode, rnode;
//只有一個運算子
if(opCounts == 1){
lchild = new TreeNode(Ran.getNumber(max), null, null);
rchild = new TreeNode(Ran.getNumber(max), null, null);
root = new TreeNode(Ran.getOperator(), lchild, rchild);
}
else{
int num1 = 0;
boolean[] place = Ran.getChildPlace(opCounts);
root = new TreeNode(Ran.getOperator(), null, null);
opeList.add(root);
for(int i = 0; i < place.length; i++){
//place[i]為true,生成一個運算子,併為該運算子生成兩個左右孩子運算數
if(place[i]){
lnode = new TreeNode(Ran.getNumber(max), null, null);
rnode = new TreeNode(Ran.getNumber(max), null, null);
//i為偶數(從0開始的),將新建立的運算子作為當前結點(運算子)的左孩子;為奇,則作為右孩子
if(i%2 == 0){
lchild = new TreeNode(Ran.getOperator(), lnode, rnode);
opeList.add(lchild);
opeList.get(num1).setLchild(lchild);
}
else{
rchild = new TreeNode(Ran.getOperator(), lnode, rnode);
opeList.add(rchild);
opeList.get(num1).setRchild(rchild);
}
}
//place[i]為false,則只生成一個運算數,組裝到當前運算子的左右孩子
else{
if(i%2 == 0){
lchild = new TreeNode(Ran.getNumber(max), null, null);
opeList.get(num1).setLchild(lchild);
}
else{
rchild = new TreeNode(Ran.getNumber(max), null, null);
opeList.get(num1).setRchild(rchild);
}
}
//num1為偶數,說明當前結點還未生成有孩子,num1不變;若是奇數,則+1
num1 = num1 + i%2;
}
}
CalAndVal();//生成完二叉樹進行校驗
}
2.2.2 隨機生成運算子結點位置
Ran類中包含一個根據運算子個數隨機生成運算子結點位置的方法,其實現思路:
- 方法返回返回一個長度為2的boolean陣列,true元素的個數表示要新建立的運算子個數。
- 在隨機生成表示式的方法中會使用到該方法,true表示在當前結點中,建立一個以運算子為父結點,兩個運算數為葉子結點的子二叉樹,作為當前結點的左或右孩子;false則表示建立一個運算數,作為當前結點的左或右孩子。
- 若運算子個數為2,則需要再建立一個運算子,所以true,false各一個。
- 運算子個數為3,則需要再建立兩個運算子。元素都是true。
public static boolean[] getChildPlace(int num){
boolean[] result = new boolean[]{true, true};
if(num==2){
Random random = new Random();
if(random.nextBoolean()){
result[0] = false;
}else {
result[1] = false;
}
}
return result;
}
2.2.3 校驗表示式
校驗表示式包括對除數為0,減法運算結果為負的情況的處理。
- 若除數為0,替換除號為其他運算子。
- 若減法結果為負,交換被減數和減數的位置。
CalAndVal()
實際呼叫了getResult()
方法,該方法獲取當前結點對應的運算結果並按以上規則校驗。
public String getResult(){
//若有子節點,說明當前結點是運算子
if(hasChild()){
switch(str){
case "+":
return Calculator.add(getLchild().getResult(), getRchild().getResult());
case "-":
String subResult = Calculator.sub(getLchild().getResult(), getRchild().getResult());
//若返回值為-1,交換左右孩子
if(subResult.contains("-")){
swapChild();
return Calculator.sub(getLchild().getResult(), getRchild().getResult());
}
else {
return subResult;
}
case "x":
return Calculator.mul(getLchild().getResult(), getRchild().getResult());
case "÷":
String divResult = Calculator.division(getLchild().getResult(), getRchild().getResult());
//返回結果為-1,表示除數為0,替換運算子
if(divResult.contains("-")){
while(str.equals("÷")){
//將當前運算子轉換為其他運算子
str = Ran.getOperator();
}
return this.getResult();
}
else {
return divResult;
}
}
}
//無子節點,說明當前結點是葉子結點,直接返回結點值
return str;
}
3. 測試
輸入命令-n 6 -r 10
(生成6道題目,最大值為10(不包括10)),生成的題目和答案如下:
題目:(在當前目錄下的expFile.txt
中)
答案:(在當前目錄下的answer.txt
中)
4. 小結
4.1 黃博曉
-
跟別人合作開發要注意溝通好。
-
資料結構很重要。
-
使用搜索引擎有時可以極大的提高效率...
4.2 凌文宇
-
基礎真的很重要,以後要繼續努力才能更好的和隊友合作
-
全程大佬帶飛,以後要繼續加油,爭取不拖後腿
-
事先的溝通與安排是必不可少的
參考連結
https://www.cnblogs.com/echoing/p/7878954.html
https://blog.csdn.net/kuku713/article/details/12684509