UML软件工程组织

 

一次简单的集成测试

2008-05-16 作者:子木清风 来源:51testing

 

一次简单的集成测试测试Card类,Card类需要使用Suit类和Cfg类,这两个类在这之前已经完成了测试。在这一步需要将三者集成在一起进行测试。在测试Card类时将不再考虑对Suti和Cfg类的测试,而仅仅是考虑Card类本身的测试,针对Card类的每一个方法进行测试。

使用Jtest自动生成测试代码,查看测试代码后发现,仅自动生成了部分测试代码,并且没有根据需要输入适合的值,我们需要手工完成部分测试代码。

从最复杂的一个方法开始入手。(当时我从最复杂的方法入手是因为有部分技术问题需要解决);getIcon方法返回某张纸牌所对应的图片文件,这里需要使用Cfg类,过程是根据牌的花色和分值计算出所对应的数组位置,因为返回的结果是一个Image类,所以在对比测试结果时有一些难度,而该数组并没有进行初始化,所以对比时不管测试结果如何对比的结果总是正确的。对此先对Cfg中的数组cardIcons进行初始化,这里仅始化正确结果的数组,最后进行与预期结果进行对比;代码示例如下:

Card card; //建立card类

Suit suit; //建立suit类

suit=Suit.CLUB; //suit引用

card=new Card(suit,'A'); //初始化card类

int ER=1; //预期位置是数组1

byte buffer[] = new byte[ER];

Cfg.cardIcons[ER]= Toolkit.getDefaultToolkit()。createImage(buffer);; //初始化数组1

Image RETVAL=card.getIcon();

assertEquals(Cfg.cardIcons[ER],RETVAL); //对比测试结果

注:如果不对Cfg中的数组进行初始化,则对比结果永远是正确的。
 

接下来对每一个方法进行测试,这些方法可以分为几类。

构造方法:

  • Card()
  • Card(final Card card)
  • Card(Suit suit, char value)

赋值的方法:

  • void assign (final Card rhs)
  • boolean setSuit(Suit newSuit)
  • boolean setType(char newType)

取值的方法

  • char cardType()
  • Suit getSuit()
  • String toString()

有效性判断

  • final boolean isAce()
  • final boolean isFaceCard()
  • final boolean isValid()
  • final boolean isValueCard()

运算

  • boolean equals (Object obj)
  • boolean lessThan(Card rhs)
  • char suitAsChar()
  • Image getIcon()

在这里发现当对某一个方法进行测试时可能会调用另一个方法。或者是在测试过程中需要借用另外的方法。那么这些方法本身是否有一个测试的先后顺序呢?例如:getIcon方法中调用了suitAsChar、isAce、isValueCard三个方法,先测试这三个方法是否正确,再测试getIcon方法是否正确,这样当getIcon方法出现错误时,可以确认是由于getIcon方法本身的错误还是由于suitAsChar、isAce、isValueCard三个方法中出现了错误。

手工完成每一个类的测试代码。可以使用Juint实现对已经完成的三个类的一次性完整测试。

集成测试在测试项目中加入Deck类,使用Jtest自动生测试代码。检查自动生成的测试代码发现有部分没有判断结果。对些需要手工改写测试代码。

测试AddDeck方法在测试过程中需要调用toString方法对结果进行判断。预期的结果是"Card nums=52 [AH, 2H, 3H, 4H, 5H, 6H, 7H, 8H, 9H, TH, JH, QH, KH, AD, 2D, 3D, 4D, 5D, 6D, 7D, 8D, 9D, TD, JD, QD, KD, AS, 2S, 3S, 4S, 5S, 6S, 7S, 8S, 9S, TS, JS, QS, KS, AC, 2C, 3C, 4C, 5C, 6C, 7C, 8C, 9C, TC, JC, QC, KC]" 在测试AddDeck方法的同时也对toString方法进行了测试;

测试burnIt方法

public void testBurnIt1() throws Throwable
{

Deck deck=new

Deck();

deck.addDeck(1);

deck.burnIt();

String RET=deck.toString() ;

String Exp="Card nums=0 []";

assertEquals(Exp, RET);
}

先增加一幅牌然后调用burnIt方法清除,使用toString方法取得返回结果,对返回结果进行判断。也可以使用getCards方法对测试结果进行判断。个人觉得getCards方法可能更加适合,因为该方法中并没有任何操作,不会对测试产生影响。下面的测试方法

会不会更好一些呢?

public void testBurnIt1() throws Throwable
{

Deck deck=new Deck();

deck.addDeck(1);

deck.burnIt();

Vector RET=deck.getCards();

assertEquals(0, RET.size());
}

测试getCard方法testGetCard1测试使用取边界值与预期值进行比较判断测试正确性的测试策略。下例为取第一个值;

public void testGetCard1() throws Throwable
{

Deck deck=new Deck();

deck.addDeck( 1);

Card card=deck.getCard();

Card card2=new Card();

boolean RET1=card.equals( card2);

assertEquals(true,RET1);
}

下面的例子中,测试了Deck类的异常情况;在测试过程中测试出现异常(不是错误)。对于这个例子我们是否需要考虑这种特殊情况呢?在BJ 这个项目中会不会出现不增加牌而使用牌的情况呢?对于这种情况是否需要考虑程序的整体架构呢?(这种异常可能会由其他的代码来处理)

public void testGetCard3() throws Throwable
{

Deck deck=new Deck();

Card card = null;

card=deck.getCard();

assertEquals(null,card);
}

测试getCards方法testGetCards1测试用例判断返回长度是否正确;

public void testGetCards1() throws Throwable
{

Deck deck=new Deck();

deck.addDeck(1);

Vector deckcard=deck.getCards();

assertEquals(52,deckcard.size());
}

testGetCards2测试用例从返回的结果中取任意值判断内容是否正确;

public void testGetCards2() throws Throwable
{

Deck deck=new Deck();

deck.addDeck(1);

Vector deckcard=deck.getCards();

Card card=(Card) deckcard.elementAt(1);

String RET=card.toString();

assertEquals("2H",RET);
}

测试shuffle方法testShuffle1用例测试在未增加牌时shuffle方法是否会出错;

public void testShuffle1() throws Throwable
{

Deck deck=new Deck();

deck.shuffle();

Vector RET=deck.getCards();

assertEquals(0, RET.size());
}

testShuffle2用例测试洗牌后纸牌的内容有没有丢失或改变;代码中使用了穷举的方法,验证每一张牌是否真实存在。是否有更好的测试方法呢?

public void testShuffle2() throws Throwable
{

Deck deck=new Deck();

Deck deck2=new Deck();

deck.addDeck( 1);

deck2.addDeck( 1);

Vector carddeck= deck.getCards();

Vector carddeck2= deck2.getCards();

deck.shuffle();

Card card,card2;

boolean RET;

for(int j=0;j<52;j++){

card=(Card) carddeck.elementAt( j);

RET=false;

for(int i=0;i<52;i++){

card2=(Card) carddeck2.elementAt(i);

if(card2.toString().equals( card.toString()))

RET=true;

}

assertEquals(true,RET);

}
}

testShuffle3用例测试洗牌后牌的数量是否错误。

public void testShuffle3() throws Throwable
{

Deck deck=new Deck();

deck.addDeck( 1);

deck.shuffle();

Vector RET=deck.getCards();

assertEquals(52, RET.size());
}

注:由于在源代码中已经注明只使用一幅牌,所以测试过程中未考虑牌多于一幅的情况;

思考问题:

  • 是否考虑异常情况?在本次的例子中,当不增加纸牌而取某一张牌时会出现错误,但是否有必要进行这种测试?
  • 在getCard方法中如果测试者不知道Card类如何使用,那么将无法对测试结果进行判断。当设计文档编写的不够细致时会不会对白盒测试阻碍,这个阻碍会有多大呢?
  • 测试shuffle方法是否有更好的方法呢?类似这种情况在实际应用中可能会很多,有时可能无法使用穷举、边界值、分类等方法来进行测试,这时应该如何进行测试呢?
  • 由于测试代码的增多,提高了错误存在于测试代码中的风险,这时应该如何处理呢?
  • 考虑testBurnIt1测试,当toString方法改变时,可能会引起testBurnIt1测试失败,这样会增加测试代码的维护难度,应该如何解决这一问题呢?