• 2018-2019-2 20175236实验二《Java面向对象程序设计》实验报告


    实验内容

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

    实验要求

    1. 没有Linux基础的同学建议先学习《Linux基础入门(新版)》《Vim编辑器》 课程
    2. 完成实验、撰写实验报告,实验报告以博客方式发表在博客园,注意实验报告重点是运行结果,遇到的问题(工具查找,安装,使用,程序的编辑,调试,运行等)、解决办法(空洞的方法如“查网络”、“问同学”、“看书”等一律得0分)以及分析(从中可以得到什么启示,有什么收获,教训等)。报告可以参考范飞龙老师的指导
    3. 严禁抄袭,有该行为者实验成绩归零,并附加其他惩罚措施。

    实验步骤

    一、单元测试

    三种代码
    要了解并养成用写三种代码来编程的习惯

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

    举个例子:我们要在一个MyUtil类中解决一个百分制成绩转成“优、良、中、及格、不及格”五级制成绩的功能。

    先写伪代码,伪代码与具体编程语言无关,不要写与具体编程语言语法相关的语句,伪代码从意图层面来解决问题,最终,伪代码产品代码最自然的、最好的注释。

    百分制转五分制:
    如果成绩小于60,转成“不及格”
    如果成绩在60与70之间,转成“及格”
    如果成绩在70与80之间,转成“中等”
    如果成绩在80与90之间,转成“良好”
    如果成绩在90与100之间,转成“优秀”
    其他,转成“错误”

    写完伪代码后,就可以用特定的编程语言翻译一下,就是可用的产品代码了。这里使用JavaMyUtil.java:

    public class MyUtil{
    public static String percentage2fivegrade(int grade){
    //如果成绩小于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 "错误";
    }
    }

    一般来说产品代码出来后,大部分工作可以说是完成了,但是,谁能保证你的产品代码不会出现bug或者错误呢?所以这个时候就需要编写测试代码,通过测试代码能够更好的完善最后的产品代码~

    在IDEA中我们可以借助单元测试工具JUnit来辅助进行TDD,直接点击Create Test就可以了

    而且,测试代码仅测试一种情况往往是不够的,通常来说会进行三个方面的测试:
    正常情况

    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));
    }
    }

    异常情况

    import org.junit.Test;
    import junit.framework.TestCase;
    public class MyUtilTest extends TestCase {
    @Test
    public void testException() {
    assertEquals("错误", MyUtil.percentage2fivegrade(-55));
    assertEquals("错误", MyUtil.percentage2fivegrade(105));
    }
    }

    边界情况

    import org.junit.Test;
    import junit.framework.TestCase;
    public class MyUtilTest extends TestCase {
    @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));
    }
    }
    • 如果测试通过就会显示test passed

    • 如果测试没通过,则会显示红色,并显示test failed,而且会告知哪里出了错误

    通过最后的测试代码的成功测试后,我们的产品代码才算是真正的完工了。当然,测试代码的编写不能随意,应该尽可能地考虑周全,才能很好的完善产品代码

    二、TDD(Test Driven Devlopment, 测试驱动开发)

    1.先写测试代码,再写产品代码的TDD的一般步骤如下:

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

    2.TDD的编码节奏是:

    • 增加测试代码,JUnit出现红条
    • 修改产品代码
    • JUnit出现绿条,任务完成

    3.老师给的StringBuffer 的例子 积极主动敲代码,使用JUnit学习Java

    public class StringBufferDemo{
    public static void main(String [] args){
    StringBuffer buffer = new StringBuffer();
    buffer.append('S');
    buffer.append("tringBuffer");
    System.out.println(buffer.length());
    System.out.println(buffer.charAt(1));
    System.out.println(buffer.capacity();
    System.out.println(buffer.indexOf("tring"));
    System.out.println("buffer = " + buffer.toString());
    }
    }

    首先我们需要改写一下例子中的程序,使其能够使用TDD来测试。改代码之前我们得知道StringBufferDemo类中的方法都是什么功能,才能知道我们需要测试哪些内容。通过查阅资料,得知

    • StringBuffer( ):分配16个字符的缓冲区
    • length():返回字符串的长度
    • charAt(int i) :返回此序列中指定索引处的 char 值。第一个 char 值在索引 0 处,第二个在索引 1 处,依此类推
    • capacity():返回string分配的存储容量
    • indexOf(String s):返回输入的子字符串的第一个字母在母字符串的位置

    最后的出的产品代码:

    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);
    }
    }

    通过IDEA中的TDD写出的测试代码:

    import junit.framework.TestCase;
    import org.junit.Test;
    public class StringBufferDemoTest extends TestCase {
    StringBuffer a = new StringBuffer("zhuyueniupi");//(<=16)
    StringBuffer b = new StringBuffer("zhuyueniupizhuyueniupi");//(>16&&<=34)
    StringBuffer c = new StringBuffer("zhuyueniupizhuyueniupizhuyueniupi");//(>=34)
    @Test
    public void testcharAt() throws Exception{
    assertEquals('z',a.charAt(0));
    assertEquals('u',a.charAt(2));
    assertEquals('p',a.charAt(9));
    assertEquals('i',a.charAt(10));
    }
    @Test
    public void testcapacity() throws Exception{
    assertEquals(27,a.capacity());
    assertEquals(38,b.capacity());
    assertEquals(49,c.capacity());
    }
    @Test
    public void testlength() throws Exception{
    assertEquals(11,a.length());
    assertEquals(22,b.length());
    assertEquals(33,c.length());
    }
    @Test
    public void testindexOf() throws Exception{
    assertEquals(0,a.indexOf("zh"));
    assertEquals(3,a.indexOf("yueniu"));
    assertEquals(7,a.indexOf("iupi"));
    }
    }

    测试运行截图:

    三、面向对象三要素

    • 抽象
      程序设计中,抽象包括两个方面,一是过程抽象,二是数据抽象

    例如:打印“1-100”这种大数据的时候

    public void printn(int n){
    for(int i=1; i<=n; i++)
    System.out.println(n);
    }

    而且能够快速打印

    printn(3);
      • 封装、继承与多态
        面向对象(Object-Oriented)的三要素包括:封装、继承、多态。
        包括:面向对象分析(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,依赖倒置原则)

    四、练习

    • 要求:使用TDD的方式设计关实现复数类Complex
    • 伪代码:
    // 定义属性并生成getter,setter
    double RealPart;
    double ImagePart;
    // 定义构造函数
    public Complex()
    public Complex(double R,double I)
    //Override Object
    public boolean equals(Object obj)
    public String toString()
    // 定义公有方法:加减乘除
    Complex ComplexAdd(Complex a)
    Complex ComplexSub(Complex a)
    Complex ComplexMulti(Complex a)
    Complex ComplexDiv(Complex a)
    • 产品代码:
    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(ra.r-ia.i,ra.i+ia.r);
    }
    Complex ComplexDiv(Complex a){
    return new Complex((ra.r+ia.i)/(a.ra.r+a.ia.i),(ia.r-ra.i)/(a.ra.r+a.ia.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));
    }
    }

    五、实验中遇到的问题

    在使用Junit的时候,import junit.framework.TestCase; 中的Junit 显示红色

    提示是程序包org.junti不存在,后来通过百度查找解决了这个问题

    • @Test 是红色的
      在老师的博客中有解决方法

    直接File 中点击Project Structure ,然后找到Modules 里的Dependencies 添加junit.jar

    其中对于junit.jar 的地址查询可以用Everything软件快捷查到

    PSP(Personal Software Process)时间


    步骤耗时百分比
    需求分析 40min 20%
    设计 60min 30%
    代码实现 70min 30%
    测试 20min 10%
    分析总结 20min 10%

  • 相关阅读:
    8.13实习报告
    8.10实习报告
    8.9实习报告
    8.8实习报告
    8.7实习报告
    关于线索二叉树建立和遍历
    main函数的位置可以任意
    返回指针值的函数和函数指针的区别
    runtime error: store to address 0x625000002048 with insufficient space for an object of type 'double' (solution.c) 0x625000002048: note: pointer points here
    m=-n++
  • 原文地址:https://www.cnblogs.com/wff666999/p/10732843.html
Copyright © 2020-2023  润新知