实验二《Java面向对象程序设计》

TDD与单元测试

前期准备:

什么是单元测试?

单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如Java里单元指一个类。

正如想用程序解决问题时,如博客Intellj IDEA 简易教程所说,要会写三种码:

  • 伪代码
  • 产品代码
  • 测试代码

什么是TDD?

TDD(Test Driven Devlopment, 测试驱动开发)先写测试代码,然后再写产品代码的开发方法叫“测试驱动开发”(TDD)。

TDD的一般步骤如下:

  • 明确当前要完成的功能,记录成一个测试列表
  • 快速完成编写针对此功能的测试用例
  • 测试代码编译不通过(没产品代码呢)
  • 编写产品代码
  • 测试通过
  • 对代码进行重构,并保证测试通过(重构下次实验练习)
  • 循环完成所有功能的开发

Junit配置

步骤十分简单:下载junit.jar包并引入即可,但是由于不熟练还是遇到了很多的问题:

  • 第一次引入jar包之后误以为不需要再度引入:实际上每次需要运用TDD或者写测试类时都需重新引入。(数据库jar包同理)

  • 测试类名一定要以Test开头,否则会报错:

    在修改过后:

任务一:实现百分制成绩转成“优、良、中、及格、不及格”五级制成绩的功能

  • 伪代码:

    百分制转五分制:
    如果成绩小于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 "错误";
    }
    }

  • 测试代码:需要兼顾正常情况异常情况边界情况

    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 testException(){//异常情况
    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));
    }
    }

测试代码运行截图:

任务二:以TDD的方式研究学习StringBuffer

  • 产品代码

    public class StringBufferDemo{
    StringBuffer str=new StringBuffer();
    StringBufferDemo(StringBuffer str){
    this.str=str;
    }
    public char charAt(int i){
    return str.charAt(i);
    }
    public int capacity(){
    return str.capacity();
    }
    public int length(){
    return str.length();
    }
    public int indexOf(String buf) {
    return str.indexOf(buf);
    }
    }
  • 测试代码

    import junit.framework.TestCase;
    import org.junit.Test; 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(){
    assertEquals('S',a.charAt(0));
    assertEquals('B',a.charAt(6));
    assertEquals('r',a.charAt(11));
    }
    @Test
    public void capacityTest(){
    assertEquals(16,a.capacity());
    assertEquals(34,b.capacity());
    assertEquals(70,c.capacity());
    }
    @Test
    public void testlength(){
    assertEquals(12,a.length());
    assertEquals(24,b.length());
    assertEquals(36,c.length());
    }
    @Test
    public void testindexOf(){
    assertEquals(0,a.indexOf("Str"));
    assertEquals(6,a.indexOf("Buff"));
    assertEquals(10,a.indexOf("er"));
    }
    }
测试代码运行结果截图

思考题

老师在博客中《积极主动敲代码,使用JUnit学习Java》提出了思考题:

capacity()超过16个字符会再分配18个字符的空间。那超过34个字符呢?你猜猜capacity()的返回值(52?54?56?还是其他值)并修改上面的代码验证一下。

在自己测试之后感觉规律是:capacity*2+2,查询资料之后在博客关于StringBuff对象的capacitya方法返回值中得到了验证:

在上述测试代码与结果中也得到体现。

面向对象三要素:封装、继承、多态

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:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。(Softeware entities like classes,modules and functions should be open for extension but closed for modifications.)

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.)

任务三:对MyDoc类进行扩充,让其支持Float类

在仅实现Integer类时,UML图是正确的,但是一旦考虑到实现其他类的功能就会违反OCP原则

实验题目:让系统支持Float类,并在MyDoc类中添加测试代码表明添加正确

正确的UML如下:

  • 代码:
abstract class Data{//Data类:打印数据
abstract public void Display();
}
class Integer extends Data{//Data的子类
int value;
Integer(){
value=5310;
}
public void Display(){//方法重写
System.out.println(value);
}
}
class Float extends Data{//Data的子类
float value;
Float(){
value=165310.2f;
}
public void Display() {//方法重写
System.out.println(value);
}
}
abstract class Factory{
abstract public Data CreatDataObject();//抽象类:创造指定数据类型,所有数据类型的父类
}
class IntegerFactory extends Factory{//Integer类,Factory子类
public Data CreatDataObject(){//方法重写
return new Integer();
}
}
class FloatFactory extends Factory{//Byte类,Factory子类
public Data CreatDataObject(){//方法重写
return new Float();
}
}
class Documents{
Data pd;
Documents(Factory pf){
pd=pf.CreatDataObject();//使pd是数据类型的上转型对象
}
public void displayData(){//调用pd子类,即不同数据类型重写的对象
pd.Display();
}
}
public class MyDoc{
static Documents b;
public static void main(String[] args) {
b=new Documents(new FloatFactory());
b.displayData();
}
}
  • 运行结果截图:

  • 启发:

    在本次试验后我们进行的结对实验,在实现Language的语言选择功能时,学习模仿了本次的实验思想,实现了S.O.L.I.D原则。

任务四:以TDD的方式开发一个复数类Complex

回顾之前的实验过程,以TDD的方式进行编程

  • 伪代码:

    1)属性:复数包含实部和虚部两个部分,
    double RealPart;复数的实部
    double ImagePart;复数的虚部
    getRealPart():返回复数的实部
    getImagePart();返回复数的虚部
    setRealPart():设置复数的实部
    setImagePart();设置复数的虚部
    输出形式:a+bi
    (2)方法:
    ①定义构造函数
    public Complex()
    public Complex(double R,double I)
    ②定义公有方法:加减乘除
    Complex ComplexAdd(Complex a):实现复数加法
    Complex ComplexSub(Complex a):实现复数减法
    Complex ComplexMulti(Complex a):实现复数乘法
    Complex ComplexDiv(Complex a):实现复数除法
    ③Override Object
    public String toString():将计算结果转化为字符串形式并输出
  • 以TDD方式编写代码:

  • 测试代码:

    import junit.framework.TestCase;
    import org.junit.Test; public class ComplexTest extends TestCase {
    Complex a=new Complex(0,0);
    Complex b=new Complex(1,1);
    Complex c=new Complex(-1,-1);
    Complex d=new Complex(20.16,53.10);
    Complex e=new Complex(2,3);
    @Test
    public void testgetReal(){
    assertEquals(0.0,a.getRealPart());
    assertEquals(-1.0,c.getRealPart());
    assertEquals(20.16,d.getRealPart());
    }
    @Test
    public void testgetIma(){
    assertEquals(0.0,a.getImagePart());
    assertEquals(-1.0,c.getImagePart());
    assertEquals(53.1,d.getImagePart());
    }
    @Test
    public void testComAdd(){
    assertEquals("0.0",b.ComplexAdd(c).toString());
    assertEquals("1.0+i",a.ComplexAdd(b).toString());
    assertEquals("19.16+52.1i",c.ComplexAdd(d).toString());
    assertEquals("-1.0-i",a.ComplexAdd(c).toString());
    assertEquals("21.16+54.1i",b.ComplexAdd(d).toString());
    }
    @Test
    public void testComSub(){
    assertEquals("1.0+i",b.ComplexSub(a).toString());
    assertEquals("-21.16-54.1i",c.ComplexSub(d).toString());
    assertEquals("2.0+2.0i",b.ComplexSub(c).toString());
    }
    @Test
    public void testComMul(){
    assertEquals("0.0",a.ComplexMulti(d).toString());
    assertEquals("-1.0-i",b.ComplexMulti(c).toString());
    assertEquals("-20.16-53.1i",c.ComplexMulti(d).toString());
    assertEquals("40.32+159.3i",d.ComplexMulti(e).toString());
    }
    @Test
    public void testComDiv(){
    assertEquals("0.0",a.ComplexDiv(b).toString());
    assertEquals("-1.0-i",c.ComplexDiv(b).toString());
    assertEquals("-0.5-0.3333333333333333i",c.ComplexDiv(e).toString());
    assertEquals("10.08+17.7i",d.ComplexDiv(e).toString());
    }
    }
  • 产品代码:

    public class Complex {
    double a,b;
    Complex(double m,double n){//构造函数设置实部虚部
    a=m;
    b=n;
    }
    public double getRealPart(){//返回实部
    return a;
    } public double getImagePart() {//返回虚部
    return b;
    }
    public Complex ComplexAdd(Complex y){//加法
    double m=y.getRealPart();
    double n=y.getImagePart();
    double x=a+m;
    double z=b+n;
    return new Complex(x,z);
    }
    public Complex ComplexSub(Complex y){
    double m=y.getRealPart();
    double n=y.getImagePart();
    double x=a-m;
    double z=b-n;
    return new Complex(x,z);
    }
    public Complex ComplexMulti(Complex y){
    double m=y.getRealPart();
    double n=y.getImagePart();
    double x=a*m;
    double z=b*n;
    return new Complex(x,z);
    }
    public Complex ComplexDiv(Complex y){
    double m=y.getRealPart();
    double n=y.getImagePart();
    double x=a/m;
    double z=b/n;
    return new Complex(x,z);
    } @Override
    public java.lang.String toString() {
    String s="";
    if (a!=0&&b>0&&b!=1){
    s+= a+"+"+ b+"i";
    }
    else if(a!=0&&b==1){
    s+=a+"+i";
    }
    else if (a!=0&&b<0&&b!=-1){
    s+= a+""+b+"i";
    }
    else if (a!=0&&b==-1){
    s+=a+"-i";
    }
    else if (a!=0&&b==0){
    s+=a;
    }
    else if (a==0&&b!=0){
    s+=b+"i";
    }
    else if (a==0&&b==0){
    s+="0.0";
    }
    return s;
    }
    }
  • 实验运行结果:

任务五:使用StarUML对实验二中的代码进行建模

UML 的基本介绍

  • UML由3个要素构成:UML的基本构造块、支配这些构造块如何放置在一起的规则和运用于整个语言的公用机制。
  • UML有3种基本的构造块:事物、关系和图。
  • 事物是对模型中最具有代表性的成分的抽象,包括结构事物,如类(Class)、接口(Interface)、协作(Collaboration)、用例(UseCase)、主动类(ActiveClass)、组件(Component)和节点(Node);行为事物,如交互(Interaction)、态机(Statemachine)、分组事物(包,Package)、注释事物(注解,Note)。
  • 关系用来把事物结合在一起,包括依赖、关联、泛化和实现关系。

UML绘制

StarUML已经有For MAC版本,本次绘图就是通过StarUML完成的,本次实验中没有运用多个类的实验,所以以书上代码为示例绘制:

实验总结与体会

本次实验最大的收获是:

  • 技能

    • 学会使用Junit测试代码
    • 学会利用StarUML绘制UML
  • 元知识

    • 深刻理解学习了S.O.L.I.D原则,尤其是OCPDIP原则
    • 学会使用TDD编程方法

    PSP表格

    步骤 需求分析 百分比
    需求分析 20min 7.1%
    设计 20min 7.1%
    代码实现 80min 28.6%
    测试 80min 42.9%
    分析总结 40min 14.3%

20165310_Exp2实验二《Java面向对象程序设计》的更多相关文章

  1. 实验二 Java面向对象程序设计

    实验二 Java面向对象程序设计 实验内容 1. 初步掌握单元测试和TDD 2. 理解并掌握面向对象三要素:封装.继承.多态 3. 初步掌握UML建模 4. 熟悉S.O.L.I.D原则 5. 了解设计 ...

  2. 20145213《Java程序设计》实验二Java面向对象程序设计实验报告

    20145213<Java程序设计>实验二Java面向对象程序设计实验报告 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装,继承,多态 初步掌握UML建模 熟悉S.O. ...

  3. 20145206《Java程序设计》实验二Java面向对象程序设计实验报告

    20145206<Java程序设计>实验二Java面向对象程序设计实验报告 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O. ...

  4. 20145308刘昊阳 《Java程序设计》实验二 Java面向对象程序设计 实验报告

    20145308刘昊阳 <Java程序设计>实验二 Java面向对象程序设计 实验报告 实验名称 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面相对象三要素:封 ...

  5. 20145113 实验二 Java面向对象程序设计

    20145113 实验二 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 1.初 ...

  6. JAVA课程实验报告 实验二 Java面向对象程序设计

    北京电子科技学院(BESTI) 实     验    报     告 课程:Java程序设计  班级:1353  姓名:韩玉琪  学号:20135317 成绩:             指导教师:娄嘉 ...

  7. 20145225唐振远 实验二 "Java面向对象程序设计"

    20145225<Java程序设计> 实验二 Java面向对象程序设计 实验报告 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S ...

  8. 20145208 实验二 Java面向对象程序设计

    20145208 实验二 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 了解设计模式 实验步 ...

  9. 20162311 实验二 Java面向对象程序设计 实验报告

    实验二 Java面向对象程序设计 实验内容 1. 初步掌握单元测试和TDD 2. 理解并掌握面向对象三要素:封装.继承.多态 3. 初步掌握UML建模 4. 熟悉S.O.L.I.D原则 5. 了解设计 ...

  10. 20162317袁逸灏 第八周实验报告:实验二 Java面向对象程序设计

    20162317袁逸灏 第八周实验报告:实验二 Java面向对象程序设计 实验内容 初步掌握单元测试和TDD 理解并掌握面向对象三要素:封装.继承.多态 初步掌握UML建模 熟悉S.O.L.I.D原则 ...

随机推荐

  1. 记录一下自己的.tmux.conf,.vimrc

    ~/.tmux.conf set -g default-terminal "screen-256color" set -g prefix C-a bind C-a send-pre ...

  2. 在django项目中自定义manage命令(转)

    add by zhj 是我增加的注释 原文:http://www.cnblogs.com/holbrook/archive/2012/03/09/2387679.html 我们都用过Django的dj ...

  3. mysql 操作sql语句 操作数据库

    sql语句 #1. 操作文件夹 创建数据库:create database db1 charset utf8; 查数据库:show databases; mysql> create databa ...

  4. SqlServer--bat批处理执行sql语句1-osql

    首先需要知道,此处使用的批处理命令是osql ,如果安装了SqlServer,目录类似: D:\Program Files\Microsoft SQL Server\100\Tools\Binn 脚本 ...

  5. 【剑指offer】旋转数组的最小数字

    一.题目: 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素. 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个 ...

  6. spring boot 中用@value给static变量赋值

    需求:改写一个JedisUtils,工具类,所以最好用静态方法和变量. @value("${redis.host}") private static String redisHos ...

  7. Python3之socket编程

    一.socket的定义 Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口.在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后 ...

  8. 实现对多维数组按照某个键值排序的两种方法(array_multisort和array_sort)

    实现对多维数组按照某个键值排序的两种解决方法(array_multisort和array_sort): 第一种:array_multisort()函数对多个数组或多维数组进行排序.    //对数组$ ...

  9. js时钟

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  10. Jason使用

    Jason是一种数据传输时候的一种格式,类似XML. package liferay; import java.beans.IntrospectionException; import java.be ...