技术开发 频道

浅论单元测试的内部输入问题

  内部输入有以下几种情形:

  自然内部输入

  这是指对底层函数的正常调用即可获得的内部输入,前面的示例就属于自然输入。代码一中Compare()函数,int a1 = GetArea(r);可以自然取得外接正方形的面积。如果外接矩形面积a1要得到某个预期的值,要传递合适的半径r。自然输入有两个条件:一是底层函数存在,二是底层函数正确。

  不可控的内部输入

  是指调用实际代码,但实际代码的输出难于控制,难于把各种可能输出都测试到。例如,底层函数返回一个随机数,就是不可控。在实际项目中,不可控是很常见的,下面的代码是空调控制程序中的一个函数(代码清单4.3.cpp):

  /*

  函数说明:

  功能: 空调控制程序片断,取得环境温度并计算制冷器需运行的时间

  参数: pWorkTime, 输出参数,保存制冷器需运行的时间

  返回: int类型,如果函数执行失败,返回0,否则返回非0值

  */

  extern int GetTemperature(int* pTemperature);

  int gExpectTemperature = 25;

  int WorkTime(int* pWorkTime)

  {

  int success = 0; //取环境温度是否成功

  int temperature; //环境温度

  ////取环境温度

  success = GetTemperature(&temperature);

  if(!success)

  return 0;

  //后面的代码与_03_WorkTime2完全一致

  //计算温度差,gExpectTemperature是全局变量

  int TempDiff = temperature - gExpectTemperature;

  if(TempDiff <= 0)

  return 0;

  if(pWorkTime == 0)

  return 0;

  //为了简化问题,这里假设温差一度,需运行一分钟

  *pWorkTime = TempDiff * 60;

  return 1;

  }

  代码的重点在于success = GetTemperature(&temperature);,这行代码调用GetTemperature()取环境温度,如果操作成功,success等于1,操作不成功,success等于0;取得的环境温度保存在局部变量int temperature中。假设在实际环境中测试,调用的都是实际代码。我们首先要设定预期的温度gExpectTemperature,例如设为25,这是全局变量,容易做到。我们还要测试各种环境温度下程序的行为,例如,至少要测试25,大于25和小于25三种情况,显然,这是很困难的,真实的环境温度在短时间内很难大幅变化,即使大幅变化,也未必符合测试需求,这就是不可控。

  失真的内部输入

  失真是打桩造成的,是打桩的必然后果。上面的示例,假如GetTemperature()未实现,或者由于解耦合的目的必须隔离,或者试图解决不可控的问题打桩来代替,桩代码大致是这个样子(代码清单4.4.cpp):

  int GetTemperature(int* pTemperature)

  {

  return 0;

  }

  直接返回0,此外什么也不做。调用GetTemperature()后,success总是为0,环境温度temperature未初始化,测试无法进行。

  一种思路是修改桩代码,使它实现一些功能,例如,给每个用例起一个名字,桩代码判断当前用例名并做合适的操作。这种方法比较麻烦,并且只能适应简单情形。一个桩可能被多个被测函数调用,一个被测函数又可能调用多个桩,要维护用例名与桩行为之间的匹配关系,无疑是一场噩梦。

0
相关文章