「BUAA OO Unit 1」 第一单元测试与数据构造
Part 0 前言
笔者在第二次研讨课上就第一单元测试与数据构造这一主题进行分享,这里记录课上分享的思路与内容。
构建不依赖路径的jar包、构建不依赖具体测试要求的自动化评测机框架、构建数据生成机。这三者相互解耦合,利于根据作业需求的迭代对评测机快速迭代。
以下以第一次作业评测机搭建为例,并将在Part3部分介绍本设计对迭代开发的支持。
Part 1 获取jar包
为了避免不同同学的Java项目结构目录、依赖包等的不同导致的无谓的麻烦,将Java项目打包为jar包,方法可移植性强。一种简单的获取jar包的方式可以见面向测试小白的简易评测机中的Part 2。
Part 2 自动化评测机框架
注:以下为python代码,并且需要python3.5以上版本以支持相应库
命令行运行jar包并重定向输入和输出
1 2 3 4 5 6 7 8
| import subprocess from subprocess import STDOUT, PIPE
def execute_java(stdin): cmd = ['java', '-jar', 'homework.jar'] proc = subprocess.Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT) stdout, stderr = proc.communicate(stdin.encode()) return stdout.decode().strip()
|
判定输出答案正确性
利用sympy
处理
1 2 3 4 5 6 7 8
| poly = genData() f = sympy.parse_expr(poly) strr = execute_java(poly) g = sympy.parse_expr(strr) if sympy.simplify(f).equals(g) : print("AC : " + str(cnt)) else: print("!!WA!! with " + "poly : " + poly + " YOURS: " + strr)
|
Part 3 数据生成
在Part 1中,我们利用了genData()
方法获取poly
,该模块的一种实现思路如下:
分层构造数据
依照Expr->Term->Factor
的思路,构建如下模块:
getExpr()
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import random import sympys
def getExpr(): index = random.randint(indexA, indexB) termNum = random.randint(termNumA, termNumB) str = "" for i in range(termNum): whiteNum = random.randint(whiteA, whiteB) str = str + getTerm() + getWhite(whiteNum) withIndex = random.randint(0,1) if withIndex == 1: str = "(" + str + ")**" + index return str
|
getTerm()
1 2 3 4 5 6 7 8 9 10 11
| def getTerm(): str = "" sigNum = random.randint(0,2) for i in range(sigNum): if(random.randint(0,1) == 1): str = str + "+" str = str + "-" factorNum = random.randint(factorA, factorB) for i in range(factorNum) : str = str + getFactor() return str
|
getFactor()
1 2 3 4 5 6 7 8 9 10
| def getFactor(): str = "" type = random.randint(1,3) if type == 1: str = getNum() elif type == 2: str = getPower() elif type == 3: str = getExpr() return str
|
getNum()
1 2 3 4 5 6 7 8 9
| def getNum(): str = "" pos = random.randint(0,1) if pos == 0: str = str + "-" else: str = str + "+" str = str + random.randint(A,B) return str
|
getWhite
1 2 3 4 5 6 7 8 9
| def getWhite(ct): str = "" for i in range(ct): flag = random.randint(0, 1) if flag == 0: str = str + ' ' else: str = str + '\t' return str
|
getPower()
等函数不再枚举,与之类似
Part 4 迭代开发
以上简述了对于第一次作业的评测机实现的部分细节,以下简要介绍如何针对第二三次作业的新需求迭代开发我们的评测机
新因子
对于sin
和cos
,直接利用形式化表达的表述,构建getTri()
方法,并将其扩充入getFactor()
自定义函数
设计getSelfDefineFunc()
方法,并将其扩充入getFactor()
。同时还需要设计构造自定义函数定义式。
sum
构造思路同自定义函数,需设计getSum()
复杂度控制
通过在getExpr()
等方法内设计indexName
等变量,控制随机数生成范围,保证不超过形式化表达要求。
边界情况讨论
设计常量池,包含如1,-1,2,-2,0,2147483647,-2147483647
等边界数据和易化简出错数据,同时根据需求扩充常量池。
嵌套
由上述介绍,得益于我们依照形式化表达构建数据生成器,我们可以根据其解耦合的特点在getFactor()
等模块加入其他新增可作为因子的生成器。
Part 5 组装
Part0-2介绍的三个模块具有高内聚低耦合的特点,只需要简单调用彼此即可组装完成。得益于这样的特点,我们可以快速迁移本自动化评测机。
This is copyright.