• 第九章.迭代与测试


    伟大软件三步骤:

    1.确认你的软件做客户要它做的事

    2.运用基本的OO原则来增加软件的灵活性

    3.努力实现可维护、可重用的设计。

    伟大软件的编写是迭代进行的,先针对整体轮廓操作,接着迭代应用程序的每个片段,直到完成。

    有两种方法去迭代深入应用程序的特定部件(part)。必须处理较小的功能片段(piece of functionality)。

    可以选择聚焦在应用程序的特定功能(feature)上。此方式完全关系到取出客户想要的一个功能片段,并且实现该功能,直到它完成。

    功能驱动开发(Feature Driven Development)挑出应用程序的特定功能,并且规划、分析及开发该功能,直到完成。

    也可以选择聚焦在通过应用程序的特定流程(flow)上。此方式取出通过应用程序的完整路径(具有清楚的开始与结束),并且在你的程序代码中实现该路径(path)

    用例驱动开发(Use Case Driven Development)挑出通过用例的场景(scenario),并且编写程序代码支持通过该用例的完整场景。

    两种迭代(iterating)方式皆由良好的需求(requirement)所驱动。因为需求源自客户,两种方式都是聚焦在交付客户要的东西上。

    在使用功能开发时,一次做单一功能(feature);接着迭代,一次解决一个功能,直到你完成应用程序的整个功能性(functionality)。

    在用例驱动开发中,你操作通过用例的的单一场景,接着再取出另一个场景并且完成它,直到所有场景被完成。然后再迭代下一个用例,直到所有用力都能运作。

    编写测试场景:

    测试案例(test case)不必复杂,它们知识提供一个方式,向客户展示类里的功能正常运作。

    应该为所有你能想到的可能的使用状况测试你的软件。要有想象力!

    也别忘了测试软件不正确使用的状况。你将在早期捕捉住错误,让你的客户高兴。

    测试驱动开发聚焦于让类的行为正确。

    良好的软件是通过迭代造就而成。分析、设计、再一次迭代,一次一次完成应用程序更小更小的部分。

    每当你迭代时,重新评估你的设计决策,假如它对你的设计合理,就别害怕改变。

    游戏框架我们增加了Unit  UnitTester  UnitGroup,项目架构:

    Board.java:

     1 package headfirst.gsf.board;
     2 
     3 import java.util.ArrayList;
     4 import java.util.Iterator;
     5 import java.util.List;
     6 
     7 import headfirst.gsf.unit.Unit;
     8 
     9 public class Board {
    10     
    11     private int width, height;
    12     private List tiles;
    13     
    14     public Board(int width, int height){
    15         this.width = width;
    16         this.height = height;
    17         initialize();
    18     }
    19     
    20     private void initialize(){//定义成二维数组的矩形棋盘
    21         tiles = new ArrayList(width);
    22         for(int i = 0; i < width; i++){
    23             tiles.add(i, new ArrayList(height));
    24             for(int j = 0; j < height; j++){
    25                 ((ArrayList) tiles.get(i)).add(j, new Tile());
    26             }
    27         }
    28     }
    29     
    30     public Tile getTile(int x, int y){
    31         return (Tile) ((ArrayList) tiles.get(x - 1)).get(y - 1);
    32     }
    33     
    34     public void addUnit(Unit unit, int x, int y){
    35         Tile tile = getTile(x, y);
    36         tile.addUnit(unit);
    37     }
    38     
    39     public void removeUnits(int x, int y){
    40         Tile tile = getTile(x, y);
    41         tile.removeUnits();
    42     }
    43     
    44     public List getUnits(int x, int y){
    45         return getTile(x, y).getUnits();
    46     }
    47 }
    View Code

    Tile.java:

     1 package headfirst.gsf.board;
     2 
     3 import java.util.List;
     4 import java.util.LinkedList;
     5 
     6 import headfirst.gsf.unit.Unit;
     7 
     8 public class Tile {
     9         
    10     private List units;
    11 
    12     public Tile(){
    13         units = new LinkedList();
    14     }
    15         
    16     protected void addUnit(Unit unit){
    17         units.add(unit);
    18     }
    19         
    20     protected void removeUnit(Unit unit){
    21         units.remove(unit);
    22     }
    23     
    24     protected void removeUnits(){
    25     }
    26     
    27     protected List getUnits(){
    28         return units;
    29     }
    30 }
    View Code

    Unit.java:

     1 package headfirst.gsf.unit;
     2 
     3 import java.util.HashMap;
     4 import java.util.LinkedList;
     5 import java.util.List;
     6 import java.util.Map;
     7 
     8 public class Unit {
     9     private String type;
    10     private int id;
    11     private String name;
    12     private List weapons;
    13     private Map properties;
    14     
    15     public Unit(int id){
    16         this.id = id;
    17     }
    18     
    19     public int getId(){
    20         return id;
    21     }
    22     
    23     //getName() and setName() methods
    24     public void setName(String name){
    25         this.name = name;
    26     }
    27     
    28     public String getName(){
    29         return name;
    30     }
    31     
    32     //getType() and setType() methods
    33     public void setType(String type){
    34         this.type = type;
    35     }
    36     
    37     public String getType(){
    38         return type;
    39     }
    40     
    41     public void addWeapon(List weapon){
    42         if(weapon == null){
    43             weapon = new LinkedList();
    44         }
    45         weapons.add(weapon);
    46     }
    47     
    48     public List getWeapons(){
    49         return weapons;
    50     }
    51     
    52     public void setProperty(String property, Object value){
    53         if(properties == null){
    54             properties = new HashMap();
    55         }
    56         properties.put(property, value);
    57     }
    58     
    59     public Object getProperty(String property){
    60         if(properties == null){
    61             return null;
    62         }
    63         
    64         return properties.get(property);
    65     }
    66 }
    View Code

    UnitGroup.java:

     1 package headfirst.gsf.unit;
     2 
     3 import java.util.HashMap;
     4 import java.util.Iterator;
     5 import java.util.LinkedList;
     6 import java.util.List;
     7 import java.util.Map;
     8 
     9 public class UnitGroup {
    10     private Map units;
    11     
    12     public UnitGroup(List unitList){
    13         units = new HashMap();
    14         for(Iterator i = unitList.iterator(); i.hasNext();){
    15             Unit unit = (Unit) i.next();
    16             units.put(unit.getId(), unit);
    17         }
    18     }
    19     
    20     public UnitGroup(){
    21         this(new LinkedList());
    22     }
    23     
    24     public void addUnit(Unit unit){
    25         units.put(unit.getId(), unit);
    26     }
    27     
    28     public void removeUnit(int id){
    29         units.remove(id);
    30     }
    31     
    32     public void removeUnit(Unit unit){
    33         removeUnit(unit.getId());
    34     }
    35     
    36     public Unit getUnit(int id){
    37         return (Unit) units.get(id);
    38     }
    39     
    40     public List getUnits(){
    41         List unitList = new LinkedList();
    42         for(Iterator i = units.entrySet().iterator(); i.hasNext();){
    43             Unit unit = (Unit) i.next();
    44             unitList.add(unit);
    45         }
    46         
    47         return unitList;
    48     }
    49 }
    View Code

    UnitTester.java:

     1 package headfirst.gsf.unit;
     2 
     3 public class UnitTester {
     4     public void testType(Unit unit, String type, String expectedOutputType){
     5         System.out.println("
    Testing setting/getting the type property.");
     6         unit.setType(type);
     7         String outputType = unit.getType();
     8         if(expectedOutputType.equals(outputType)){
     9             System.out.println("Test passed");
    10         }else{
    11             System.out.println("Test failed: " + outputType + " didn't match " + expectedOutputType);
    12         }
    13     }
    14     
    15     public void testUnitSpecificProperty(Unit unit, String propertyName, Object inputValue, Object expectedOutputValue){
    16         System.out.println("
    Testing setting/getting a unit-specific property.");
    17         unit.setProperty(propertyName, inputValue);
    18         Object outputValue = unit.getProperty(propertyName);
    19         if(expectedOutputValue.equals(outputValue)){
    20             System.out.println("Test passed");
    21         }else{
    22             System.out.println(" Test failed: " + outputValue + " didn't match " + expectedOutputValue);
    23         }
    24     }
    25     
    26     public void testChangeProperty(Unit unit, String propertyName, Object inputValue, Object expectedOutputValue){
    27         System.out.println("
    Testing changing an existing property's value.");
    28         unit.setProperty(propertyName,  inputValue);
    29         Object outputValue = unit.getProperty(propertyName);
    30         if(expectedOutputValue.equals(outputValue)){
    31             System.out.println("Test passed");
    32         }else{
    33             System.out.println("Test failed: " + outputValue + " didn't match " + expectedOutputValue);
    34         }
    35     }
    36     
    37     public void testNonExistentProperty(Unit unit, String propertyName){
    38         System.out.println("
    Testing getting a non-existent property's value.");
    39         Object outputValue = unit.getProperty(propertyName);
    40         if(outputValue == null){
    41             System.out.println("Test passed");
    42         }else{
    43             System.out.println("Test failed with value of " + outputValue);
    44         }
    45     }
    46     
    47     public static void main(String args[]){
    48         UnitTester tester = new UnitTester();
    49         Unit unit = new Unit(1000);
    50         tester.testType(unit, "infantry", "infantry");
    51         tester.testUnitSpecificProperty(unit, "hitPoints", new Integer(25), new Integer(25));
    52         tester.testChangeProperty(unit, "hitPoints", new Integer(15), new Integer(15));
    53         tester.testNonExistentProperty(unit, "strength");
    54     }
    55 }
    View Code

    编程契约(programming contract):当你按契约编程(programming by contract)时,你与软件的用户正同意该软件以特定方式行动。

    Unit的契约,假使使用它的人是能干的程序设计师,他们能处理返回值为null的情况,因此我们的契约是,当你请求不存在的特性或武器,你能处理null值。

    若你不信任客户:

    你可能将Unit类中getProperty()方法重写:

     1 public Object getProperty(String property) throws IllegalAccessException{
     2         if(properties == null){
     3             throw new IllegalAccessException("What are you doing? No properties");
     4         }
     5         Object value = properties.get(property);
     6         if(value == null){
     7             throw new IllegalAccessException("You're screwing up! No property value.");
     8         }else{
     9             return value;
    10         }
    11     }
    View Code

    如果他们不信任你:

    他们会保护他们的程序代码,并且使用防御性编程:

     1 //Some method goes out and gets a unit
     2     Unit unit = getUnit();
     3     //Now let's use the unit...
     4     String name = unit.getName();
     5     if((name != null) && (name.length() > 0)){
     6         System.out.println("Unit name: " + name);
     7     }
     8     Object value = unit.getProperty("hitPoints");
     9     if(value != null){
    10         try{
    11             Integer hitPoints = (Integer) value;
    12         }catch(ClassCastException e){
    13             //Handle the potential error
    14         }
    15     }
    View Code
  • 相关阅读:
    Day1-while and for/break and continue
    Day1-用户输入及字符串格式化输入
    Day1-python基础
    2-21-源码编译搭建LNMP环境
    2-20-使用apache搭建web网站
    2-19-mysql优化
    2-18-搭建mysql集群实现高可用
    2-17-MySQL读写分离-mysql-proxy
    2-16-2MySQL主从
    2-14-存储过程-触发器-事务
  • 原文地址:https://www.cnblogs.com/lanshanxiao/p/7218050.html
Copyright © 2020-2023  润新知