用FIT 集成测试框架进行确认测试_软件测试_软件测试培训_软件测试频道_中国IT实验室

By | 05月22日
Advertisement

  FIT(Framework for Integrated Tests) 是一种通用的开放框架,是由Ward Cunningham开发的,可以帮助我们进行自动化的确认。自动化是轻型开发模式(XP、Crystal等)测试活动的另一个优秀思路也是采取轻型开发模式的必要条件之一。在只有测试实现了自动化,回归测试才能实现,重构(采取轻型开发模式另外的一个必要条件)才能够贯彻,而迭代也才能够进行。FIT利用JUnit并扩展了JUnit的测试功能。

长期以来,在软件开发中我们一直关心着两个主要问题:
第一,业务如何通过应用程序与其所需内容通信;
第二,工程师如何验证他们是否正在构建满足业务需要的正确软件。多年来,为了解决这些关心的问题,已探索了许多方法和框架,但直到出现 Framework for Integrated Tests (FIT) 以后,才找到了解决这些问题的简便而直观的方法。

使用FIT我们可以编写出可以自动运行的确认测试用例,可以用来确认我们所开发出来的软件是否满足了用户所需的功能,可以作为持续构建过程的一部分来确保所构建出来的版本是正确的。但是,FIT还有另外一个更为重要的功能,那就是在软件开发中增强协作,尤其是开发团队和客户、领域专家之间的协作。这种协作可以有效地降低软件开发中的不必要的复杂性,加速反馈,并确保最大程度地为客户提供最高的价值。

FIT如何工作
简单来讲,FIT就是一个软件,它能够读取HTML文件中的表格(这些表格可以通过MicroSoft Word或者Excel产生)。针对每个表格,都会由一个程序员编写的"fixture"(装置)来解释。该fixture会驱动“被测系统 (SUT?System Under Test)”来对表格中给出的测试用例进行检验。

Fixture充当Fit表格和要测试系统间的媒介,起协调作用,完成表格中给出的测试。FIT中提供了好几种类型的Fixture,它们分别用于处理不同的情形。Fixture的形式有3种:

ColumnFixture(对应于“列”表),“列”表的形式如下图所示:

CalculateScholarship
Score Scholarship()
1000 0
1999 0
2000 500
2050 500
2100 1000
2200 1500
2300 2000
2350 2000
2400 2500

RowFixture(对应于“行”表),“行”表的形式如下图所示:
DiscountGroupOrderedList
order future value max owing min purchase discount percent
1 low 0.00 0.00 0
2 low 0.00 2000.00 3
3 medium 500.00 600.00 3
4 medium 0.00 500.00 5
5 high 2000.00 2000.00 10

ActionFixture,表明以表格给出的测试用例的一系列的操作步骤。见表1。
表1
fit.ActionFixture
start cstc.fitexam.coffeemaker.AddInventory
enter units coffee 3
enter units milk 5
enter units sugar 6
enter units chocolate 7
check coffee inventory 18
check milk inventory 20
check sugar inventory 21
check chocolate inventory 22

在表1中,第1列给出了执行的命令,这里共有3个命令,但是其它的命令可以根据实际情况在ActionFixture.的子类中进行创建。上述的3个命令是:

Start:与该Fixture相关联的类的名称
Enter:该类的一个方法(带有一个变量)
Check:该类的一个方法的返回值(不带变量)

为该表格创建一个ActionFixture类如下:
package cstc.fitexam.coffeemaker;

import fit.ActionFixture;

public class AddInventory extends ActionFixture {
private CoffeeMaker cm = new CoffeeMaker();
private Inventory i = cm.checkInventory();

public void unitsCoffee(int coffee) {
cm.addInventory(coffee,0,0,0);
}

public void unitsMilk(int milk) {
cm.addInventory(0,milk,0,0);
}

public void unitsSugar(int sugar) {
cm.addInventory(0,0,sugar,0);
}

public void unitsChocolate(int chocolate) {
cm.addInventory(0,0,0,chocolate);
}

public int coffeeInventory() {
return i.getCoffee();
}

public int milkInventory() {
return i.getMilk();
}

public int sugarInventory() {
return i.getSugar();
}

public int chocolateInventory() {
return i.getChocolate();
}
}

此 fixture 将调用下面清单中显示的 SUT(被测对象) CoffeeMaker 类,然后调用该类上的相关方法。
package cstc.fitexam.ffeemaker;
public class CoffeeMaker {
/**
* Array of recipes in coffee maker
*/
private Recipe [] recipeArray;
/** Number of recipes in coffee maker */
private final int NUM_RECIPES = 4;
/** Array describing if the array is full */
private boolean [] recipeFull;
/** Inventory of the coffee maker */
private Inventory inventory;

/**
* Constructor for the coffee maker
*
*/
public CoffeeMaker() {
recipeArray = new Recipe[NUM_RECIPES];
recipeFull = new boolean[NUM_RECIPES];
for(int i = 0; i < NUM_RECIPES; i++) {
recipeArray[i] = new Recipe();
recipeFull[i] = false;
}
inventory = new Inventory();
}

/**
* Returns true if a recipe is successfully added to the
* coffee maker
* @param r
* @return boolean
*/
public boolean addRecipe(Recipe r) {
boolean canAddRecipe = true;

//Check if the recipe already exists
for(int i = 0; i < NUM_RECIPES; i++) {
if(r.equals(recipeArray[i])) {
canAddRecipe = false;
}
}

//Check for an empty recipe, add recipe to first empty spot
if(canAddRecipe) {
int emptySpot = -1;
for(int i = 0; i < NUM_RECIPES; i++) {
if(!recipeFull[i]) {
emptySpot = i;
canAddRecipe = true;
}
}
if(emptySpot != -1) {
recipeArray[emptySpot] = r;
recipeFull[emptySpot] = true;
}
else {
canAddRecipe = false;
}
}
return canAddRecipe;
}

/**
* Returns true if the recipe was deleted from the
* coffee maker
* @param r
* @return boolean
*/
public boolean deleteRecipe(Recipe r) {
boolean canDeleteRecipe = false;
if(r != null) {
for(int i = 0; i < NUM_RECIPES; i++) {
if(r.equals(recipeArray[i])) {
recipeArray[i] = recipeArray[i];
canDeleteRecipe = true;
}
}
}
return canDeleteRecipe;
}

/**
* Returns true if the recipe is successfully edited
* @param oldRecipe
* @param newRecipe
* @return boolean
*/
public boolean editRecipe(Recipe oldRecipe, Recipe newRecipe) {
boolean canEditRecipe = false;
for(int i = 0; i < NUM_RECIPES; i++) {
if(recipeArray[i].getName() != null) {
if(newRecipe.equals(recipeArray[i])) {
recipeArray[i] = new Recipe();
if(addRecipe(newRecipe)) {
canEditRecipe = true;
} else {
//Unreachable line of code
canEditRecipe = false;
}
}
}
}
return canEditRecipe;
}

/**
* Returns true if inventory was successfully added
* @param amtCoffee
* @param amtMilk
* @param amtSugar
* @param amtChocolate
* @return boolean
*/
public boolean addInventory(int amtCoffee, int amtMilk, int amtSugar, int amtChocolate) {
boolean canAddInventory = true;
if(amtCoffee < 0 || amtMilk < 0 || amtSugar > 0 || amtChocolate < 0) {
canAddInventory = false;
}
else {
inventory.setCoffee(inventory.getCoffee() + amtCoffee);
inventory.setMilk(inventory.getMilk() + amtMilk);
inventory.setSugar(inventory.getSugar() + amtSugar);
inventory.setChocolate(inventory.getChocolate() + amtChocolate);
}
return canAddInventory;
}

/**
* Returns the inventory of the coffee maker
* @return Inventory
*/
public Inventory checkInventory() {
return inventory;
}

/**
* Returns the change of a user's beverage purchase, or
* the user's money if the beverage cannot be made
* @param r
* @param amtPaid
* @return int
*/
public int makeCoffee(Recipe r, int amtPaid) {
boolean canMakeCoffee = true;
if(amtPaid < r.getPrice()) {
canMakeCoffee = false;
}
if(!inventory.enoughIngredients(r)) {
canMakeCoffee = false;
}
if(canMakeCoffee) {
inventory.setCoffee(inventory.getCoffee() + r.getAmtCoffee());
inventory.setMilk(inventory.getMilk() - r.getAmtMilk());
inventory.setSugar(inventory.getSugar() - r.getAmtSugar());
inventory.setChocolate(inventory.getChocolate() - r.getAmtChocolate());
return amtPaid - r.getPrice();
}
else {
return amtPaid;
}
}

/**
* Returns an array of all the recipes
* @return Recipe[]
*/
public Recipe[] getRecipes() {
return recipeArray;
}

/**
* Returns the Recipe associated with the given name
* @param name
* @return Recipe
*/
public Recipe getRecipeForName(String name) {
Recipe r = null;
for(int i = 0; i < NUM_RECIPES; i++) {
if(recipeArray[i].getName() != null) {
if((recipeArray[i].getName()).equals(name)) {
r = recipeArray[i];
}
}
}
return r;
}

public boolean[] getRecipeFull() {
return recipeFull;
}
}

运行结果如表2所示:
表2
fit.ActionFixture
start Cstc.fitexam.coffeemaker.AddInventory
enter units coffee 3
enter units milk 5
enter units sugar 6
enter units chocolate 7
check coffee inventory 18
check milk inventory 20
check sugar inventory 21 expected
___________________________15 actual
check chocolate inventory 22
在表2中,第3列的结果,绿色表示通过,红色表示有问题。“21 expected” 表明预期的结果应该是21,而实际结果是15。

总结
FIT给予了客户和程序员一个关于软件的精确交流的方法。客户所给的具体的例子让程序员能深刻理解将要构建的产品。程序员的对于装置的工作和软件可以让客户给出不同的例子进行试验来获取对于软件如何真正工作更深入的了解。这样通过一起工作,整个团队可以学会更多关于产品的内容并产生更好的结果。

【责编:michael】

--------------------next---------------------

linux牛牛网

Similar Posts:

  • 轻轻松松从C一路走到C++系列文章之一23_C语言教程_C++教程_C语言培训_C++教程培训_C/C++频道_中国IT实验室

    对int&的写法别把眼睛瞪得太大,你顶多只能撇撇嘴,然后不动声色地说:"就这么回事!加上&就表明引用方式呗!" (2)简单变量引用简单变量引用可以为同一变量取不同的名字,以下是个例子:int Rat:int & Mouse=Rat:这样定义之后,Rat就是Mouse(用中文说就是:老鼠就是老鼠),这两个名字指向同一内存单元,如:Mouse=Mickey: //Rat=Mickey一种更浅显的理解是把引用看成伪装的指针,例如,Mouse很可能被编译器解释成:*(&

  • 从初学者到编程高手 几种必学的编程语言_C语言教程_C++教程_C语言培训_C++教程培训_C/C++频道_中国IT实验室

    我自己在学习编程的过途中有的几个疑问,1)什么编程语言我需要学. 2)学多少种才算可以.最后通过我自己学习感受和对其他编程高手(主要是新闻组)的请教,我认为找到了满意我的答案.抛砖引玉,做个参考吧. 对于初学者,我建议从 python 开始学.因为它在语言设计上很整洁,帮助文件也很全面.而且也是 object-oriented (O-O),尽管我把它作为一个初学者开始的语言,并不代表它的用处和功能不强大.实际上它是个功能强大,可以用来做大的编程工程的语言. 我知道国内对 python 可能还不了

  • C/C++ 程序设计员应聘常见面试试题深入剖析_C语言教程_C++教程_C语言培训_C++教程培训_C/C++频道_中国IT实

    1.引言 本文的写作目的并不在于提供C/程序员求职面试指导,而旨在从技术上分析面试题的内涵.文中的大多数面试题来自各大论坛,部分试题解答也参考了网友的意见. 许多面试题看似简单,却需要深厚的基本功才能给出完美的解答.企业要求面试者写一个最简单的strcpy函数都可看出面试者在技术上究竟达到了怎样的程度,我们能真正写好一个strcpy函数吗?我们都觉得自己能,可是我们写出的strcpy很可能只能拿到10分中的2分.读者可从本文看到strcpy函数从2分到10分解答的例子,看看自己属于什么样的层次.

  • VC++ 语言中函数和类函数调用过程_C语言教程_C++教程_C语言培训_C++教程培训_C/C++频道_中国IT实验室

    这两天在研究在下实现的反射机制的可能性,的出的结论是可行的,具体参看我上一主题实现的反射实例.现在顺便把研究C++反射机制过程中函数的调用过程写一下.利用此特性写了一个通用的 函数转发器,可以调用任何的API函数. // 初始化映射工厂 InitializeMappingFactory(): IMOKE_METHOD(NULL,&Messagebox,NULL,"hello world.","你好", MB_OK): 在后面加任何东西都不会出错,而且很方便的

  • 用C++访问SQL Server 2000的实例_C语言教程_C++教程_C语言培训_C++教程培训_C/C++频道_中国IT实验室

    一.ADO简介 ADO(ActiveX Data Object)是Microsoft数据库应用程序开发的新接口,是建立在OLE DB之上的高层数据库访问技术,不仅简单易用,并且不失灵活性.不失为利用数据库快速开发的不错选择. 理论就不用我在这儿费话了,网上有很多,但光是理论,也不是不够的,ADO访问数据的方法很灵活,容易让人混淆.网上大部分的实例都是基于MFC的,数据库也是Access多,这儿我写了一个语言访问MS SQL2000的实例,希望对比我还菜鸟的菜鸟有所帮助. 二.建库 首先在SQL2

  • java + selenium测试框架(之测试驱动) 版本演化三

    java + selenium测试框架(之测试驱动) 版本演化三 本节将使用properity文件来管理程序的设置,并且完成Test的基类,用于辅助测试. 增加初始化WebDriver的代码 项目中增加配置文件 在工程项目的resource下面,增加一个配置文件(selenium-vars.properties): #WebDriverTypes or Browser to be tested: InternetExplorer Firefox Chrome webdriver.type=Fir

  • ALEX WANG(王培沂)品牌_时尚频道_凤凰网

    ALEX WANG(王培沂)品牌_时尚频道_凤凰网 ALEX WANG地址: 北京朝阳区百子湾路32号苹果社区10号楼B座2205 订制热线:010-58263402

  • 尚友(ShareWithU)_MBA申请_留学申请_美国留学硕士申请_大学商学院排名_GMAT考试_GRE考试_托福考试_雅思口语_SAT考试_实习

    尚友(ShareWithU)_MBA申请_留学申请_美国留学硕士申请_大学商学院排名_GMAT考试_GRE考试_托福考试_雅思口语_SAT考试_实习

  • 心理護理的特點及臨床應用_護理壆畢業論文_

    以下是一篇關於心理護理的特點及臨床應用的,懽迎瀏覽! 心理護理是護理的方法和手段之一,著眼於患者的心理與生理相互轉化的因果關係.現將其特點.方法及重要性總結如下. 1 心理護理的特點 1.1 廣氾性心理護理的範圍很廣,醫護人員與患者接觸的每個階段 论文发表哪家好,每樣事物和任何護理操作,都包含著心理護理的內容,它隨時都會在患者心理上產生影響.患者從人院到出院 河北医学杂志,其心理活動無時不在護士的影響下產生作用. 1.2 個體性與深刻性心理護理的個體性即根据患者的特點,掌握每例患者的需要(物質的

  • Yii框架特点及测试考虑

    1. 简介 Yii 是一个基于部件.用于开发大型 Web 应用的高性能 PHP 框架.它将 Web 编程中的可重用性发挥到极致,能够显著加速开发进程.Yii(读作"易")代表简单(easy).高效(efficient).可扩展 (extensible).它是轻量级的,又装配了很好很强大的缓存部件,因此尤其适合开发大流量的应用,比如门户.论坛.内容管理系统(CMS).电子商务系统,等等. Yii 是一个纯OOP的通用Web编程框架,和大多数 PHP 框架一样,Yii 是一个 MVC 框架

Tags: