一、单元测试和TDD
用程序解决问题时,要学会写以下三种代码:
伪代码产品代码测试代码 正确的顺序应为:伪代码(思路)→ 测试代码(产品预期功能)→ 产品代码(实现预期功能),这种开发方法叫“测试驱动开发”(TDD)。TDD的一般步骤如下: 明确当前要完成的功能,记录成一个测试列表 快速完成编写针对此功能的测试用例 测试代码编译不通过(没产品代码呢) 编写产品代码 测试通过基于TDD,可以有效避免过度开发的现象,因为我们只需要让测试通过即可。
一:
实现百分制成绩转成“优、良、中、及格、不及格”五级制成绩的功能首先用伪代码理思路:
如果成绩小于60,转成“不及格” 如果成绩在60与70之间,转成“及格” 如果成绩在70与80之间,转成“中等” 如果成绩在80与90之间,转成“良好” 如果成绩在90与100之间,转成“优秀” 其他,转成“错误”其次,选择一种语言把伪代码实现,也就成了产品代码
public class MyUtil{
public static String percentage2fivegrade(int grade){ //如果成绩小于0,转成“错误” if ((grade < 0)) return "错误"; //如果成绩小于60,转成“不及格” else 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 "优秀"; //如果成绩大于100,转成“错误” else return "错误"; } }- 测试代码不就是多次调用System.out.println():
public class MyUtilTest {
public static void main(String[] args) { if(MyUtil.percentage2fivegrade(55) != "不及格") System.out.println("test failed!"); else if(MyUtil.percentage2fivegrade(65) != "及格") System.out.println("test failed!"); else if(MyUtil.percentage2fivegrade(75) != "中等") System.out.println("test failed!"); else if(MyUtil.percentage2fivegrade(85) != "良好") System.out.println("test failed!"); else if(MyUtil.percentage2fivegrade(95) != "优秀") System.out.println("test failed!"); else System.out.println("test passed!"); } }二、
以TDD的方式研究学习StringBuffer自己写JUnit测试用例:
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.length()); System.out.println(buffer.indexOf("tring")); System.out.println("buffer = " + buffer.toString());对于这个程序,有有四个方面来测试,charAt()、capacity()、length()、indexOf产品代码如下:
public class StringBufferDemo{
StringBuffer buffer = new StringBuffer(); public StringBufferDemo(StringBuffer buffer){ this.buffer = buffer; } public Character charAt(int i){ return buffer.charAt(i); } public int capacity(){ return buffer.capacity(); } public int length(){ return buffer.length(); } public int indexOf(String buf) { return buffer.indexOf(buf); } }- 接下来我们需要对调用各种方法的返回值进行猜测: public class StringBufferDemoTest extends TestCase { StringBuffer a = new StringBuffer("StringBuffer");//测试12个字符(<=16) StringBuffer b = new StringBuffer("StringBufferStringBuffer");//测试24个字符(>16&&<=34) StringBuffer c = new StringBuffer("StringBufferStringBufferStringBuffer");//测试36个字符(>=34) @Test public void testcharAt() throws Exception{ assertEquals('S',a.charAt(0)); assertEquals('g',a.charAt(5)); assertEquals('r',a.charAt(11)); } @Test public void testcapacity() throws Exception{ assertEquals(28,a.capacity()); assertEquals(40,b.capacity()); assertEquals(52,c.capacity()); } @Test public void testlength() throws Exception{ assertEquals(12,a.length()); assertEquals(24,b.length()); assertEquals(36,c.length()); } @Test public void testindexOf() throws Exception{ assertEquals(0,a.indexOf("Str")); assertEquals(5,a.indexOf("gBu")); assertEquals(10,a.indexOf("er")); } }
三、对MyDoc类进行扩充,让其支持Short类,初步理解设计模式。
OCP是OOD中最重要的一个原则,要求软件实体(类,模块,函数等)应该对扩充开放,对修改封闭。同时,模块的源代码是不可改动的,任何人都不许修改已有模块的源代码。已有的支持Int型的代码如下:
abstract class Data{ public abstract void DisplayValue(); } class Integer extends Data { int value; Integer(){ value=100; } public void DisplayValue(){ System.out.println(value); } } class Document { Data pd; Document() { pd=new Integer(); } public void DisplayData(){ pd.DisplayValue(); } } public class MyDoc { static Document d; public static void main(String[] args) { d = new Document(); d.DisplayData(); } }要求支持Short类,Document类要修改构造方法,这还违反了OCP原则。封装、继承、多态解决不了问题了,这时需要设计模式了:
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(); } }- 只需要class Short extends Data、class ShortFactory extends Factory即可使系统支持Short类型,测试代码如下:
public class MyDoc {
static Document d; public static void main(String[] args) { d = new Document(new ShortFactory()); d.DisplayData(); } }四、以TDD的方式开发一个复数类Complex:
TDD的编码节奏是:增加测试代码,JUnit出现红条 - 修改产品代码 - JUnit出现绿条,任务完成
测试代码:
public class ComplexTest extends TestCase { Complex c1 = new Complex(0, 3); Complex c2 = new Complex(-1, -1); Complex c3 = new Complex(2,1); @Test public void testgetRealPart() throws Exception { assertEquals(-1.0, Complex.getRealPart(-1.0)); assertEquals(5.0, Complex.getRealPart(5.0)); assertEquals(0.0, Complex.getRealPart(0.0)); } @Test public void testgetImagePart() throws Exception { assertEquals(-1.0, Complex.getImagePart(-1.0)); assertEquals(5.0, Complex.getImagePart(5.0)); assertEquals(0.0, Complex.getImagePart(0.0)); } @Test public void testComplexAdd() throws Exception { assertEquals("-1.0+2.0i", c1.ComplexAdd(c2).toString()); assertEquals("2.0+4.0i", c1.ComplexAdd(c3).toString()); assertEquals("1.0", c2.ComplexAdd(c3).toString()); } @Test public void testComplexSub() throws Exception { assertEquals("1.0+4.0i", c1.ComplexSub(c2).toString()); assertEquals("-2.0+2.0i", c1.ComplexSub(c3).toString()); assertEquals("-3.0 -2.0i", c2.ComplexSub(c3).toString()); } @Test public void testComplexMulti() throws Exception { assertEquals("3.0 -3.0i", c1.ComplexMulti(c2).toString()); assertEquals("-3.0+6.0i", c1.ComplexMulti(c3).toString()); assertEquals("-1.0 -3.0i", c2.ComplexMulti(c3).toString()); } @Test public void testComplexComplexDiv() throws Exception { assertEquals("-1.5 -1.5i", c1.ComplexDiv(c2).toString()); assertEquals("1.2+0.6i", c1.ComplexDiv(c3).toString()); assertEquals("-0.6 -0.6i", c2.ComplexDiv(c3).toString()); } }产品代码:
public class Complex{
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;}public Complex ComplexAdd(Complex c) { return new Complex(r + c.r, i + c.i);}public Complex ComplexSub(Complex c) { return new Complex(r - c.r, i - c.i);}public Complex ComplexMulti(Complex c) { return new Complex(r * c.r - i * c.i, r * c.i + i * c.r);}public Complex ComplexDiv(Complex c) { return new Complex((r * c.i + i * c.r)/(c.i * c.i + c.r * c.r), (i * c.i + r * c.r)/(c.i * c.i + c.r * c.r));}public String toString() { String s = " "; if (i > 0) s = r + "+" + i + "i"; if (i == 0) s = r + ""; if (i < 0) s = r + " " + i + "i"; return s;}
}