首页 > 代码库 > 简易四则运算生成程序——第一次改进后的单元测试

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

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

项目成员:张金生  张政

工程地址: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 { 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 = http://www.mamicode.com/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     @Test12     public void testGcd() {13         assertEquals("4", f2.gcd(f2).toString());14     }15 16     @Test17     public void testToString() {18         assertEquals("2 1/4", f1.toString());19     }20 21     @Test22     public void testAddFraction() {23         assertEquals(new Fraction(25, 4).toString(), f1.add(f2).toString());24     }25 26     @Test27     public void testMinusFraction() {28         assertEquals(new Fraction(-7, 4).toString(), f1.minus(f2).toString());29     }30 31     @Test32     public void testMultiplyFraction() {33         assertEquals(new Fraction(144, 16).toString(), f1.multiply(f2).toString());34     }35 36     @Test37     public void testDivideFraction() {38         assertEquals(new Fraction(9, 16).toString(), f1.divide(f2).toString());39     }40 41     @Test42     public void testChangeSign() {43         assertEquals(new Fraction(-9, 4).toString(), f1.changeSign().toString());44     }45 46     @Test47     public void testGetRandiomInt() {48         Fraction a = Fraction.getRandiom(7);49         System.out.println(a.toString());50     }51 52     @Test53     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     @Test23     public void testGenerateSimpleQuestion() {24         qg.generateSimpleQuestion();25     }26 27     @Test28     public void testGenerateCommonQuestion() {29         qg.generateCommonQuestion();30     }31 32     @Test33     public void testGenerateMediumQuestion() {34         qg.generateMediumQuestion();35     }36 37     @Test38     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

 

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