一、单元测试与TDD:
- 编程前需要理清思路,知道需要做什么,如何做,可以先用伪代码来描述该过程。
- 用编程语言将伪代码翻译处理后,就是产品代码了,伪代码是对产品代码最好的注释。
- 完成产品代码后,还需要测试代码来证明自己的代码没有问题,java编程对类实现的测试叫单元测试。
单元测试练习:
要求:在一个MyUtil类中解决百分制成绩转成“优,良,中,及格,不及格”五级制成绩的功能。
根据要求编写伪代码:
百分制转五分制:
如果成绩小于60,转成“不及格”
如果成绩在60与70之间,转成“及格”
如果成绩在70与80之间,转成“中等”
如果成绩在80与90之间,转成“良好”
如果成绩在90与100之间,转成“优秀”
其他,转成“错误”
翻译伪代码成产品代码:
package experiment2; public class MyUtil { public static String percentage2fivegrade(int grade){ //如果成绩小于0,转成“错误” if (grade<0) return "错误"; //如果成绩小于60,转成“不及格” if (grade<60) return "不及格"; //如果成绩在60到70之间,转成“及格” else if (grade<70) return "及格"; //如果成绩在70到80之间,转成“中等” else if (grade<80) return "中等"; //如果成绩在80到90之间,转成“良好” else if (grade<90) return "良好"; //如果成绩在90到100之间,转成“优秀” else if (grade<=100) return "优秀"; //其他,转成“错误” else return "错误"; } }
接下来是编写测试代码,检验自己的产品代码有无错误。选中MyUtil,在左边出现的小灯泡下拉菜单中选中Create Test:
接着在创建出的MyUtilTest中编写如下测试代码:
import junit.framework.TestCase; import org.junit.Test; public class MyUtilTest extends TestCase { @Test public void testNormal() { assertEquals("不及格", MyUtil.percentage2fivegrade(55)); assertEquals("及格", MyUtil.percentage2fivegrade(65)); assertEquals("中等", MyUtil.percentage2fivegrade(75)); assertEquals("良好", MyUtil.percentage2fivegrade(85)); assertEquals("优秀", MyUtil.percentage2fivegrade(95)); } @Test public void testException(){ assertEquals("错误",MyUtil.percentage2fivegrade(105)); assertEquals("错误",MyUtil.percentage2fivegrade(-55)); } @Test public void testBoundary(){ assertEquals("不及格",MyUtil.percentage2fivegrade(0)); assertEquals("及格",MyUtil.percentage2fivegrade(60)); assertEquals("中等",MyUtil.percentage2fivegrade(70)); assertEquals("良好",MyUtil.percentage2fivegrade(80)); assertEquals("优秀",MyUtil.percentage2fivegrade(90)); assertEquals("优秀",MyUtil.percentage2fivegrade(100)); } }
然后运行测试,结果无误,表示产品代码正确。
二、以TDD的方式研究学习StringBuffer:
在娄老师的博客《积极主动敲代码,使用Juit学习java》中,给出了一个用于学习StringBuffer几个方法的程序:
public class StringBufferDemo{ public static void main(String [] args){ StringBuffer buffer = new StringBuffer(); buffer.append('S'); buffer.append("tringBuffer"); System.out.println(buffer.charAt(1)); System.out.println(buffer.capacity(); System.out.println(buffer.indexOf("tring")); System.out.println("buffer = " + buffer.toString()); } }
了解这几个方法后,选择了charAt(),length(),capacity()三个方法,开始编写产品代码:
public class StringBufferDemo { StringBuffer buffer=new StringBuffer(); public Character charAt(int i){ return buffer.charAt(i); } public int length(){ return buffer.length(); } public int capacity(){ return buffer.capacity(); } }
然后开始编写测试代码,检验产品代码的正确性:
import junit.framework.TestCase; import org.junit.Test; public class StringBufferDemoTest extends TestCase { StringBuffer a=new StringBuffer("yesterday"); StringBuffer b=new StringBuffer("tomorrowisnotnow"); StringBuffer c=new StringBuffer("liveherenowtodayisneccessary"); @Test public void testcharAt(){ assertEquals('y',a.charAt(0)); assertEquals('r',b.charAt(5)); assertEquals('n',c.charAt(8)); } @Test public void testlength(){ assertEquals(9,a.length()); assertEquals(16,b.length()); assertEquals(28,c.length()); } @Test public void testcapacity(){ assertEquals(25,a.capacity()); assertEquals(32,b.capacity()); assertEquals(44,c.capacity()); } }
最终运行后显示成功,产品代码无误。
三、以TDD的方式开发一个复数类Comeplex:
要求:定义属性并生成getter,setter;定义构造函数,定义公有方法(加减乘除)。
按要求编写产品代码如下:
public class Complex { // 定义属性并生成getter,setter private double r; private double i; // 定义构造函数 public Complex(double r,double i){ this.r=r; this.i=i; } public static double getRealPart(double r){ return r; } public static double getImagePart(double i){ return i; } //Override Object public boolean equals(Object obj){ Complex complex=(Complex) obj; if (complex.r!=r) { return false; } if(complex.i!=i){ return false; } return true; } public String toString(){ String str=new String(); if (i==0) str=r+""; else if(i<0) str=r + ""+i+"i"; else str=r+""+"+"+i+"i"; return str; } // 定义公有方法:加减乘除 Complex ComplexAdd(Complex a){ return new Complex(r+a.r,i+a.i); } Complex ComplexSub(Complex a){ return new Complex(r-a.r,i-a.i); } Complex ComplexMulti(Complex a){ return new Complex(r*a.r-i*a.i,r*a.i+i*a.r); } Complex ComplexDiv(Complex a){ return new Complex((r*a.r+i*a.i)/(a.r*a.r+a.i*a.i),(i*a.r-r*a.i)/(a.r*a.r+a.i*a.i)); } }
编写测试代码检验产品代码的正确性,测试代码如下:
import junit.framework.TestCase; import org.junit.Test; public class ComplexTest extends TestCase { Complex a=new Complex(1,2); Complex b=new Complex(-2,-1); Complex c=new Complex(4,-2); Complex d=new Complex(4,-2); @Test public void testequals(){ assertEquals(false,a.equals(b)); assertEquals(false,b.equals(c)); assertEquals(true,c.equals(d)); } @Test public void testAdd(){ assertEquals(new Complex(-1,1),a.ComplexAdd(b)); assertEquals(new Complex(5,0),a.ComplexAdd(c)); } @Test public void testSub(){ assertEquals(new Complex(3,3),a.ComplexSub(b)); assertEquals(new Complex(-3,4),a.ComplexSub(c)); } @Test public void testMulti(){ assertEquals(new Complex(0,-5),a.ComplexMulti(b)); assertEquals(new Complex(8,6),a.ComplexMulti(c)); } @Test public void testDiv(){ assertEquals(new Complex(0,0.5),a.ComplexDiv(c)); assertEquals(new Complex(-0.3,-0.4),b.ComplexDiv(c)); } }
测试成功截图:
四、体会OCP原则和DIP原则的应用:
娄老师给出的设计模式示例代码如下:
// Server Classes abstract class Data { abstract public void DisplayValue(); } class Integer extends Data { int value; Integer() { value=100; } public void DisplayValue(){ System.out.println (value); } } // Pattern Classes abstract class Factory { abstract public Data CreateDataObject(); } class IntFactory extends Factory { public Data CreateDataObject(){ return new Integer(); } } //Client classes class Document { Data pd; Document(Factory pf){ pd = pf.CreateDataObject(); } public void DisplayData(){ pd.DisplayValue(); } } //Test class public class MyDoc { static Document d; public static void main(String[] args) { d = new Document(new IntFactory()); d.DisplayData(); } }
按要求用我的学号28模取余得到4,即按以下要求进行代码扩充:让系统支持Fioat类,并在MyDoc类中添加测试代码表明添加正确。
添加后代码如下:
abstract class Data { abstract public void DisplayValue(); } class Integer extends Data { int value; Integer() { value=100; } public void DisplayValue(){ System.out.println (value); } } class Float extends Data{ float value; Float(){ value=20155328; } public void DisplayValue(){ System.out.println(value); } } // Pattern Classes abstract class Factory { abstract public Data CreateDataObject(); } class IntFactory extends Factory { public Data CreateDataObject(){ return new Integer(); } } class FloatFactory extends Factory{ public Data CreateDataObject(){ return new Float(); } }
测试代码如下:
//Test class public class MyDoc { static Document d; public static void main(String[] args) { d = new Document(new FloatFactory()); d.DisplayData(); } }
最终运行成功,证明添加代码正确。
五、StarUML进行建模,画类图:
六、实验中遇到的问题及解决方法:
- 问题1:对StringBuffer的capacity()方法不太理解。
- 解决方法:参考StringBuffer中的capacity详解及实践,知道了StringBuffer的默认大小是16,当StringBuffer达到最大容量时,会将最大容量增加到原来的两倍再加2.
- 问题2:在测试Comeplex类时,出现了如下的red 把人:
- 解决方法:由运行结果可知是equals()方法的编写出现了问题,于是回到Comeplex中重新编写如下:
-
public boolean equals(Object obj){ Complex complex=(Complex) obj; if (complex.r!=r) { return false; } if(complex.i!=i){ return false; } return true; }
然后测试运行显示成功,问题解决。
七:实验感想:
- 通过这次的实验,我了解到了许多的有关java的知识,更重要的是掌握了对于一个代码编写者在编写代码时十分重要的三种代码即伪代码,产品代码和测试代码,通过编写这三种代码,可以让我们的思路更加清晰,执行过程更加顺畅,避免一些不该犯的错误,。我想,在这次的学习后,我的代码错误率应该会有所下降,编程过程更加理智科学,而不是像以前一样想到什么些什么,结果一堆bug。