测试项目:减一四则运算生成程序
项目成员:张金生 张政
工程地址:https://coding.net/u/jx8zjs/p/paperOne/git
ssh://git@git.coding.net:jx8zjs/paperOne.git
测试单元概览:
1. Fraction: 分数类,支持分数加减乘除法,约分,取相反数等
2.QuestionGen:题目生成类,支持生成各种难度的题目,和答案。
待测单元:
Fraction类:
1 public class Fraction {View Code
2 public int up;
3 public int down;
4
5 public Fraction(int up, int down) {
6 if (down == 0 || up == 0) {
7 System.out.println("divided by zero error");
8 return;
9 }
10 int smaller = up > down ? up : down;
11 int maxCommonFactor = 1;
12 for (int i = 1; i <= smaller; i++) {
13 if (up % i == 0 && down % i == 0) {
14 maxCommonFactor = i;
15 }
16 }
17
18 this.up = up / maxCommonFactor;
19 this.down = down / maxCommonFactor;
20 }
21
22
23 public Fraction gcd(Fraction f) {
24 int smaller = f.up > f.down ? f.up : f.down;
25 int maxCommonFactor = 1;
26 for (int i = 1; i <= smaller; i++) {
27 if (f.up % i == 0 && f.down % i == 0) {
28 maxCommonFactor = i;
29 }
30 }
31 f.up = f.up / maxCommonFactor;
32 f.down = f.down / maxCommonFactor;
33
34 return f;
35 }
36
37 public String toString() {
38 if (down == 1)
39 return "" + up;
40 if(Math.abs(up)/down>0){
41 return up>0?up/down+" "+up%down+"/"+down:"-"+Math.abs(up)/down+" "+Math.abs(up)%down+"/"+down;
42 }
43 return up + "/" + down;
44 }
45
46 public Fraction add(Fraction f) {
47 Fraction a = new Fraction(up, down);
48 a.up = f.up * a.down + a.up * f.down;
49 a.down = a.down * f.down;
50
51 return a.gcd(a);
52 }
53
54 public Fraction minus(Fraction f) {
55 Fraction a = new Fraction(up, down);
56 a.up = a.up * f.down - f.up * a.down;
57 a.down = a.down * f.down;
58
59 return a.gcd(a);
60 }
61
62 public Fraction multiply(Fraction f) {
63 Fraction a = new Fraction(up, down);
64 a.up = a.up * f.up;
65 a.down = a.down * f.down;
66 return a.gcd(a);
67 }
68
69 public Fraction divide(Fraction f) {
70 Fraction a = new Fraction(up, down);
71 a.up = a.up * f.down;
72 a.down = a.down * f.up;
73 return a.gcd(a);
74 }
75
76 public Fraction changeSign(){
77 up = -up;
78 return this;
79 }
80
81 public static Fraction getRandiom(int Max) {
82 return new Fraction((int) (Math.random() * Max / 2) + 1, (int) (Math.random() * Max / 2) + 1);
83 }
84
85 public static Fraction getRandiom(int Max, boolean isInt) {
86 return new Fraction((int) (Math.random() * Max / 2) + 1, isInt ? 1 : (int) (Math.random() * Max / 2) + 1);
87 }
QuestionGen类待测单元:
1 public String generateSimpleQuestion() {View Code
2 SupportedOperation[] operation = { SupportedOperation.ADD, SupportedOperation.MINUS };
3 return generateQuestion(2, 0, 20, operation, false, false);
4 }
5
6 public String generateCommonQuestion() {
7 SupportedOperation[] operation = { SupportedOperation.ADD, SupportedOperation.MINUS,
8 SupportedOperation.MULTIPLY, SupportedOperation.DIVIDE };
9 return generateQuestion(4, 0, 20, operation, false, true);
10 }
11
12 public String generateMediumQuestion() {
13 SupportedOperation[] operation = { SupportedOperation.ADD, SupportedOperation.MINUS,
14 SupportedOperation.MULTIPLY, SupportedOperation.DIVIDE };
15 return generateQuestion(4, 0, 20, operation, true, true);
16 }
17
18 public String generateComplexQuestion() {
19 SupportedOperation[] operation = { SupportedOperation.ALL };
20 return generateQuestion(6, 0, 20, operation, true, true);
21 }
22
23 public String answer;
24
25 Stack<SupportedOperation> oplist = new Stack<SupportedOperation>();
26 Stack<Fraction> numlist = new Stack<Fraction>();
27 ArrayList<Integer[]> bclist;
28 TreeMap<Integer, Integer> frequency;
29 TreeMap<Integer, Integer> direction;
30
31 private void getBcPrint(int numOfOperand) {
32 bclist = new ArrayList<Integer[]>();
33 if (numOfOperand > 2) {
34 int bcnum = (int) (Math.random() * (numOfOperand - 2));
35 for (int n = 0; n < bcnum; n++) {
36 Integer[] bracket = new Integer[2];
37 bracket[0] = (int) (Math.random() * (numOfOperand - 2));
38 bracket[1] = (int) (Math.random() * (numOfOperand - 2 - bracket[0]) + bracket[0]);
39 if (bracket[0] == bracket[1]) {
40 bracket[1]++;
41 }
42 boolean canput = true;
43 for (int i = 0; i < bclist.size(); i++) {
44 Integer[] tmp = bclist.get(i);
45 if (bracket[0] < tmp[0] & bracket[1] >= tmp[0] & bracket[1] < tmp[1]) {
46 canput = false;
47 break;
48 } else if (bracket[1] > tmp[1] & bracket[0] > tmp[0] & bracket[0] <= tmp[1]) {
49 canput = false;
50 break;
51 } else if (bracket[0] == tmp[0] & bracket[1] == tmp[1]) {
52
53 }
54 }
55 if (canput) {
56 bclist.add(bracket);
57 }
58 }
59
60 }
61 frequency = new TreeMap<Integer, Integer>();
62 direction = new TreeMap<Integer, Integer>();
63 for (int i = 0; i < bclist.size(); i++) {
64 Integer[] tmp = bclist.get(i);
65 if (frequency.containsKey(tmp[0])) {
66 frequency.put(tmp[0], frequency.get(tmp[0]) + 1);
67 } else {
68 frequency.put(tmp[0], 1);
69 direction.put(tmp[0], 0);
70 }
71 if (frequency.containsKey(tmp[1])) {
72 frequency.put(tmp[1], frequency.get(tmp[1]) + 1);
73 } else {
74 frequency.put(tmp[1], 1);
75 direction.put(tmp[1], 1);
76 }
77 }
78 }
79
80 public Fraction getanswer(ArrayList<Fraction> frlist, SupportedOperation[] so) {
81
82 numlist.push(frlist.get(0));
83 for (int n = 0; n < so.length; n++) {
84 switch (so[n]) {
85 case ADD:
86 oplist.push(so[n]);
87 numlist.push(frlist.get(n + 1));
88 break;
89 case MINUS:
90 oplist.push(SupportedOperation.ADD);
91 numlist.push(frlist.get(n + 1).changeSign());
92 break;
93 case MULTIPLY: {
94 Fraction r = numlist.pop().multiply(frlist.get(n + 1));
95 numlist.push(r);
96 }
97 break;
98 case DIVIDE: {
99 Fraction r = numlist.pop().divide(frlist.get(n + 1));
100 numlist.push(r);
101 }
102 break;
103 default:
104 System.out.println("不支持的运算");
105 break;
106 }
107 }
108
109 while (!oplist.isEmpty()) {
110 Fraction answer = numlist.pop();
111 switch (oplist.pop()) {
112 case ADD: {
113 answer = answer.add(numlist.pop());
114 numlist.push(answer);
115 }
116 break;
117 // case MINUS: {
118 // answer = answer.minus(numlist.pop());
119 // numlist.push(answer);
120 // }
121 // break;
122 default:
123 System.out.println("不支持的运算");
124 break;
125 }
126
127 }
128
129 return numlist.pop();
130 }
QuestionGen核心题目生成单元:
1 public String generateQuestion(int numOfOperand, int rangeMin, int rangMax, SupportedOperation[] operation,View Code
2 boolean isFractional, boolean hasbracket) {
3 String question = "";
4 int[] ioperands = null;
5 ArrayList<Fraction> af = new ArrayList<Fraction>();
6 SupportedOperation[] so = null;
7 if (numOfOperand < 2) {
8 System.out.println("操作数数量至少为2");
9 return "";
10 }
11 if (rangMax > 500) {
12 System.out.println("操作数数最大值不能超过500");
13 return "";
14 }
15 getBcPrint(numOfOperand);
16 if (!isFractional) {
17 ScriptEngine se = new ScriptEngineManager().getEngineByName("JavaScript");
18 ioperands = new int[numOfOperand];
19 for (int i = 0; i < numOfOperand; i++) {
20 ioperands[i] = (int) (Math.random() * rangMax / 2 + 1);
21
22 }
23 so = new SupportedOperation[numOfOperand - 1];
24 for (int i = 0; i < operation.length; i++) {
25 if (operation[i] == SupportedOperation.ALL) {
26 operation = new SupportedOperation[4];
27 operation[0] = SupportedOperation.ADD;
28 operation[1] = SupportedOperation.MINUS;
29 operation[2] = SupportedOperation.MULTIPLY;
30 operation[3] = SupportedOperation.DIVIDE;
31
32 }
33 }
34 // 除法運算,保证整除
35 int value = 0;
36 for (int j = numOfOperand - 1; j > 0; j--) {
37 so[numOfOperand - 1 - j] = operation[(int) (Math.random() * operation.length)];
38 }
39 for (int j = numOfOperand - 2; j >= 0; j--) {
40 if (so[j] == SupportedOperation.DIVIDE) {
41 if (value < 1) {
42 ioperands[j] = ioperands[j] * ioperands[j + 1];
43 value++;
44
45 } else {
46 so[j] = operation[(int) (Math.random() * (operation.length - 2))];
47 }
48 }
49 }
50 // 输出括号
51 for (int i = 0; i < numOfOperand - 1; i++) {
52 if (frequency.containsKey(i)) {
53 if (direction.get(i) == 0) {
54 for (int k = 0; k < frequency.get(i); k++) {
55 question += "(";
56 }
57 }
58 }
59 question += ioperands[i];
60 if (frequency.containsKey(i)) {
61 if (direction.get(i) == 1) {
62 for (int k = 0; k < frequency.get(i); k++) {
63 question += ")";
64 }
65 }
66 }
67 question += so[i];
68 }
69 if (frequency.containsKey(numOfOperand - 1)) {
70 if (direction.get(numOfOperand - 1) == 0) {
71 for (int k = 0; k < frequency.get(numOfOperand - 1); k++) {
72 question += "(";
73 }
74 }
75 }
76 question += ioperands[numOfOperand - 1];
77 if (frequency.containsKey(numOfOperand - 1)) {
78 if (direction.get(numOfOperand - 1) == 1) {
79 for (int k = 0; k < frequency.get(numOfOperand - 1); k++) {
80 question += ")";
81 }
82 }
83 }
84
85 try {
86 Integer d = (Integer) se.eval(question);
87 answer = "" + d;
88 } catch (Exception e) {
89 generateQuestion(numOfOperand, rangeMin, rangMax, operation, isFractional, hasbracket);
90 }
91
92 } else {
93 for (int i = 0; i < numOfOperand; i++) {
94 af.add(Fraction.getRandiom(rangMax));
95 }
96
97 so = new SupportedOperation[numOfOperand - 1];
98 for (int i = 0; i < operation.length; i++) {
99 if (operation[i] == SupportedOperation.ALL) {
100 operation = new SupportedOperation[4];
101 operation[0] = SupportedOperation.ADD;
102 operation[1] = SupportedOperation.MINUS;
103 operation[2] = SupportedOperation.MULTIPLY;
104 operation[3] = SupportedOperation.DIVIDE;
105
106 }
107 }
108 question += af.get(0);
109 for (int j = 0; j < numOfOperand - 1; j++) {
110 so[j] = operation[(int) (Math.random() * operation.length)];
111 question += (so[j] == SupportedOperation.DIVIDE ? "÷" : so[j].toString()) + af.get(j + 1);
112
113 }
114 answer = getanswer(af, so).toString();
115 try {
116 } catch (Exception e) {
117 e.printStackTrace();
118 }
119
120 }
121
122 return question;
123
124 }
测试类:
FractionTest
1 public class FractionTest {
2
3 Fraction f1 = new Fraction(9, 4);
4 Fraction f2 = new Fraction(16, 4);
5
6 @Test
7 public void testdown0() {
8 new Fraction(0, 0);
9 }
10
11 @Test
12 public void testGcd() {
13 assertEquals("4", f2.gcd(f2).toString());
14 }
15
16 @Test
17 public void testToString() {
18 assertEquals("2 1/4", f1.toString());
19 }
20
21 @Test
22 public void testAddFraction() {
23 assertEquals(new Fraction(25, 4).toString(), f1.add(f2).toString());
24 }
25
26 @Test
27 public void testMinusFraction() {
28 assertEquals(new Fraction(-7, 4).toString(), f1.minus(f2).toString());
29 }
30
31 @Test
32 public void testMultiplyFraction() {
33 assertEquals(new Fraction(144, 16).toString(), f1.multiply(f2).toString());
34 }
35
36 @Test
37 public void testDivideFraction() {
38 assertEquals(new Fraction(9, 16).toString(), f1.divide(f2).toString());
39 }
40
41 @Test
42 public void testChangeSign() {
43 assertEquals(new Fraction(-9, 4).toString(), f1.changeSign().toString());
44 }
45
46 @Test
47 public void testGetRandiomInt() {
48 Fraction a = Fraction.getRandiom(7);
49 System.out.println(a.toString());
50 }
51
52 @Test
53 public void testGetRandiomIntBoolean() {
54 Fraction a = Fraction.getRandiom(7, true);
55 Fraction b = Fraction.getRandiom(7, true);
56 System.out.println("true = " + a.toString() + "\nfalse = " + b.toString());
57 }
58
59 }
QuestionGenTest:
1 public class QuestionGenTest {
2
3 QuestionGen qg = new QuestionGen();
4 ArrayList<Fraction> flt = new ArrayList<Fraction>();
5 SupportedOperation[] sot = { SupportedOperation.ADD, SupportedOperation.MINUS, SupportedOperation.MULTIPLY,
6 SupportedOperation.DIVIDE };
7
8 @Test
9 public void testGetanswer() {
10
11 flt.add(new Fraction(1, 2));
12 flt.add(new Fraction(1, 3));
13 flt.add(new Fraction(1, 4));
14 flt.add(new Fraction(1, 3));
15 flt.add(new Fraction(1, 2));
16
17 Fraction r = qg.getanswer(flt, sot);
18 assertEquals("2/3", r.toString());
19
20 }
21
22 @Test
23 public void testGenerateSimpleQuestion() {
24 qg.generateSimpleQuestion();
25 }
26
27 @Test
28 public void testGenerateCommonQuestion() {
29 qg.generateCommonQuestion();
30 }
31
32 @Test
33 public void testGenerateMediumQuestion() {
34 qg.generateMediumQuestion();
35 }
36
37 @Test
38 public void testGenerateComplexQuestion() {
39 qg.generateComplexQuestion();
40 }
41
42
43 }
测试结果:
Fraction类测试结果:
QuestionGen类测试结果:
单元测试总结:
单元测试时发现了一些功能或方法定义了,但在使用的时候没有用到,有些可能预计不会再用到的则选择注释掉,这样可以增加代码覆盖率。测试过的单元和功能都能成功的达到想要的预期结果。
代码覆盖率:
Fraction类测试代码覆盖率:
QuestionGen类测试代码覆盖率:
总代吗覆盖率:
代码覆盖率总结:
Fraction类的代码覆盖率能达到97.4%,确实非常高,没有测试到的部分为一些复杂的随机分支,或者减少程序出错的校验内容。QuestionGen类的代码覆盖率为74.2%,一部分未测试部分也是由于随机程度够多的时候才能完全覆盖,本次测试也运行了多次测试用例,目前显示未覆盖的部分也是可达的,还有一部分未测试行是保证程序鲁棒性的代码。因此我们认为本次测试基本达到单元测试要求。
工程地址:https://coding.net/u/jx8zjs/p/paperOne/git
ssh://git@git.coding.net:jx8zjs/paperOne.git