用程序解决问题时,要学会写如下三种代码:java
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 "优秀"; else return "错误"; } }
测试代码:app
import org.junit.Test; import junit.framework.TestCase; 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 testExceptions() { assertEquals("错误",MyUtil.percentage2fivegrade(-55)); assertEquals("错误",MyUtil.percentage2fivegrade(105)); } @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)); } }
测试结果:编程语言
老师所给程序以下:函数
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.length()); System.out.println("buffer = " + buffer.toString()); } }
根据TDD方式设计出JUnit测试用例:单元测试
charAt()
、capacity()
、length()
、indexOf()
。利用断言进行比较。charAt()
返回此序列中指定索引处的 char 值。(第一个 char 值在索引 0 处,第二个在索引 1 处,依此类推,这相似于数组索引。);capacity()
是一个获取当前实体的实际容量的方法;length()
是获取实体中存放的字符序列的长度的方法;indexOf()
是返回输入的子字符串的第一个字母在母字符串的位置的方法。因此在JUnit测试用例中设置三个容量与长度都不相同的字符串,来对capacity()
与length()
这两个方法进行更加深入的学习。测试代码:学习
import org.junit.Test; import junit.framework.TestCase; public class StringBufferDemoTest extends TestCase { StringBuffer a = new StringBuffer("StringBuffer"); StringBuffer b = new StringBuffer("StringBufferStringBuffer"); StringBuffer c = new StringBuffer("StringBufferStringBufferStringBuffer"); @Test public void testcharAt() { assertEquals('S',a.charAt(0)); assertEquals('i',a.charAt(3)); assertEquals('B',a.charAt(6)); } @Test public void testcapacity() { assertEquals(28,a.capacity()); assertEquals(40,b.capacity()); assertEquals(52,c.capacity()); } @Test public void testindexOf() { assertEquals(0,a.indexOf("String")); assertEquals(4,a.indexOf("ngB")); assertEquals(8,a.indexOf("ffer")); } @Test public void testlength() { assertEquals(12,a.length()); assertEquals(24,b.length()); assertEquals(36,c.length()); } }
测试结果:
抽象
- 抽象就是抽出事物的本质特征而暂时不考虑他们的细节。对于复杂系统问题人们借助分层次抽象的方法进行问题求解;在抽象的最高层,可使用问题环境的语言,以归纳的方式叙述问题的解。 - 编程原则DRY(Don't Repeat Yourself)
封装、继承与多态
- 接口(interface)是封装的准确描述手段。 - 面向对象(Object-Oriented)的三要素包括:封装、继承、多态。面向对象的思想涉及到软件开发的各个方面,如面向对象分析(OOA)、面向对象设计(OOD)、面向对象编程实现(OOP)。OOA根据抽象关键的问题域来分解系统,关注是什么(what)。OOD是一种提供符号设计系统的面向对象的实现过程,用很是接近问题域术语的方法把系统构形成“现实世界”的对象,关注怎么作(how),经过模型来实现功能规范。OOP则在设计的基础上用编程语言(如Java)编码。贯穿OOA、OOD和OOP的主线正是抽象。
S.O.L.I.D原则
- SRP(Single Responsibility Principle,单一职责原则) - OCP(Open-Closed Principle,开放-封闭原则) - LSP(Liskov Substitusion Principle,Liskov替换原则) - ISP(Interface Segregation Principle,接口分离原则) - DIP(Dependency Inversion Principle,依赖倒置原则)
OCP是OOD中最重要的一个原则,OCP的内容是:
- software entities (class, modules, function, etc.) should open for extension,but closed for modification.
- 软件实体(类,模块,函数等)应该对扩充开放,对修改封闭。
DIP的内容是:
- High level modules should not depend upon low level modules. Both should depend upon abstractions Abstractions should not depend upon details. Details should depend upon abstractions
- 高层模块不该该依赖于低层模块。两者都应该依赖于抽象抽象不该该依赖于细节。细节应该依赖于抽象
代码实现:
abstract class Data{ abstract public void DisplayValue(); } class Integer extends Data { int value; Integer(){ value=100; } public void DisplayValue(){ System.out.println(value); } } class Long extends Data { int value; Long(){ value=11271013; } public void DisplayValue(){ System.out.println(value); } } abstract class Factory { abstract public Data CreateDataObject(); } class IntFactory extends Factory { public Data CreateDataObject(){ return new Integer(); } } class LongFactory extends Factory { public Data CreateDataObject(){ return new Long(); } } class Document { Data pd; Document(Factory pf){ pd = pf.CreateDataObject(); } public void DisplayData(){ pd.DisplayValue(); } } public class MyDoc{ static Document d; public static void main(String [] args) { d = new Document(new IntFactory()); d = new Document(new LongFactory()); d.DisplayData(); } }
测试结果:
代码实现:
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 a) { return new Complex(r + a.r, i + a.i); } public Complex ComplexSub(Complex a) { return new Complex(r - a.r, i - a.i); } public Complex ComplexMulti(Complex a) { return new Complex(r * a.r - i * a.i, r * a.i + i * a.r); } public Complex ComplexDiv(Complex a) { return new Complex((r * a.i + i * a.r)/(a.i * a.i + a.r * a.r), (i * a.i + r * a.r)/(a.i * a.i + a.r * a.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; } }
测试代码:
import junit.framework.TestCase; import org.junit.Test; 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()); } }
测试结果:
遇到的问题:
在写JUnit测试用例时,寻找到用来测试的合适的复数比较困难。因为复数的除法较为复杂,在测试时,很容易出现无限循环的小数,致使测试失败。
如图:
本次实验内容较多,可是掌握了JUnit测试的方法,经过编写测试代码,能够测试本身代码中正常状况、异常状况、边界状况或是程序中的算法是否正确。这样减小了对于代码的重复屡次运行与数据测试,费时也费力,有时一些数据会致使运行崩溃,对电脑也有损伤。
在利用JUnit测试代码的过程当中,也掌握了对于assertEquals
的使用,对于代码中一些方法的理解也更加透彻与深入。
在实验过程当中,对于TDD方式、UML建模、S.O.L.I.D原则以及设计模式等等,也有更加深入而切身的体会。编写代码是一个须要思考与改进的过程,对本身Java的水平也是一个提升。
步骤 | 耗时 | 百分比 |
需求分析 | 10min | 17.2% |
设计 | 20min | 34.5% |
代码实现 | 8min | 13.8% |
测试 | 15min | 25.9% |
分析总结 | 5min | 8.6% |