简易四则运算生成程序——第一次改进后的单元测试

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简易四则运算生成程序——第一次改进后的单元测试相关的知识,希望对你有一定的参考价值。

测试项目:减一四则运算生成程序

项目成员:张金生  张政

工程地址:https://coding.net/u/jx8zjs/p/paperOne/git

ssh://[email protected]:jx8zjs/paperOne.git

 

测试单元概览

1. Fraction: 分数类,支持分数加减乘除法,约分,取相反数等

2.QuestionGen:题目生成类,支持生成各种难度的题目,和答案。

 

待测单元:

Fraction类:

技术分享
 1 public class Fraction {
 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     }
View Code

QuestionGen类待测单元:

技术分享
  1     public String generateSimpleQuestion() {
  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     }
View Code

QuestionGen核心题目生成单元:

技术分享
  1     public String generateQuestion(int numOfOperand, int rangeMin, int rangMax, SupportedOperation[] operation,
  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     }
View Code

测试类:

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://[email protected]:jx8zjs/paperOne.git

 

以上是关于简易四则运算生成程序——第一次改进后的单元测试的主要内容,如果未能解决你的问题,请参考以下文章

结对编程1 - 四则运算生成器的改进

(第四周)四则运算单元测试

java词频统计——改进后的单元测试

20165203 结对编程 四则运算(第一周)

简易四则运算小程序二

任务02——安装 Intellj IDEA,编写一个简易四则运算小程序,并将代码提交到 GitHub