第九章.迭代与测试

伟大软件三步骤:

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
原文地址:https://www.cnblogs.com/lanshanxiao/p/7218050.html