怎么抽取一个测试模块?

[b][/b][b]问题:[/b]
当为一个产品类编写了好几个测试,它们含有重复的代码。因为我们知道重复的代码是软件中很多问题的根源,怎么 消除代码中的重复性。

[b]背景:[/b]
为同一个产品类编写几个测试的时候,你最先注意到的模式之一就是每个测试开始的那几行代码总是很相像。每个测试都有三个基本的组成部分:创建一个对象,调用一些方法,检查结果。每个测试的第二部分总是不同的,对不同方法的调用可以区别不同的测试:"如果用这些参数调用构造方法,希望看到这样的结果;但是如果传递了空值,那么构造方法应该抛出那样的异常"。
测试的第3部分,检查结果,这完全依赖于你所调用的方法,如果测试调用的是不同的方法,当然期望的结果也是不同的。一般情况下,在这部分,只有在反复调用同一个方法的时候才会有重复代码出现。

然而,创建对象会产生测试之间的重复代码,而且绝大部分重复的代码都出现在这里,在一个类中除了构造方法以外还有很多方法需要测试,所以一旦为这个类编写了第二个测试,就重复了第一个测试中"创建一些对象"的部分,因为很可能用相同的参数调用了相同的构造方法,这样的重复代码实在是很常见,所以如果Junit能有一种内置的机制来消除它,那就再好不过了。

那么如果将要测试的对象称为测试模块:一种对象的"配置",其行为是可以预见的。这样的话,我们可以将测试第一部分----"创建一些对象"称为“创建一个测试模块”。目的是创建一些对象并且将其初始化成某种已知的状态,以便在使用它们调用一些方法的时候,可以预见到结果。

[b]技巧:[/b]
从测试中找出重复的测试模块代码,将这些代码移动到一个叫做setUp()的方法里面。修改后的代码可能不需要编译,因为现在是在setUp()方法中声明变量,然后在测试中使用这些变量。将这些变量放在实例级的参数域中,这样setUp()和测试代码都可以使用它们。因为每个测试是执行在其自己的实例中,所以不必担心在不同测试之间实例级的参数域会被错误地改变。在执行测试的时候,test runner会在每个测试之前调用setUp()方法。测试类中的每个测试都可以使用这个通用的方法初始化。

[b]代码演示:[/b]
下面代码Money JavaBean及方法就不给出,可以根据测试代码,自己推出

public class MoneyTest extends TestCase{

public void testAdd(){
Money added = new Money(12,50);
Money augend = new Money(12,50);
Money sum = added.add(augend);
assertEquals(2500,sum.inCents());
}
public void testNegate(){
Money money = new Money(12,50);
Money opposite = money.negate();
assertEquals(-1250,opposite.inCents());
}

public void testRound(){
Money money = new Money(12,50);
Money rounded = money.roundToNearestDollar();
assertEquals(1300,rounder.inCents());
}
}

注意上面的三个测试的第一行几乎是一样的,似乎可以将这个对象移到setUp()方法里。因为testAdd()方法将这个对象叫做added而其他叫money,首先需要将added相关money以使得三个测试的第一行都一样,然后就可以将这一行移到setUp()方法里去。最后,将money从一个本地变量变成一个实例级的参数域,使得setUp()和所有的测试都可以使用它。接着看看改动后的代码:

public class MoneyTest extend TestCase{
private Money money;

protected void setUp()throws Exception{
money = new Money(12,50);
}

public void testAdd(){
Money sum = added.add(augend);
assertEquals(2500,sum.inCents());

}

public void testNegate(){
Money opposite = money.negate();
assertEquals(-1250,opposite.inCents());
}

public void testRound(){
Money rounded = money.roundToNearestDollar();
assertEquals(1300,rounder.inCents());
}

}

上面这样的做,我们其实在数学中有个概念很好的用来说下:那就是[b]将方程式进行变形然后提取公因式。[/b]任何东西都是可以进行检讨和讨论

[b]讨论:[/b]
Junit通过方法setUp()和teatDown()提供了对测试模块的支持,可以在junit.framework.TestCase中找到他们。在创建TestCase的子类的时候,可以重载这些方法来为每个测试建立或者销毁测试模块。要了解Junit是如何使用这些方法的,可以查看另一个TestCase方法runBare()的代码:

public void runBare()throws Throwable{
setUp();
try{
runTest();
}
finally{
tearDown();
}
}

在执行测试的时候,框架会首先调用runBare()方法来设置一个测试模块,运行测试,然后再撤销测试模块。注意将tearDown()放在finally块中,就能保证它一定被执行,即使测试失效,这个方法是为了释放资源,避免资源浪费。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这里提供一个简单的例子来说明如何进行 case 抽取并生成相应的测试用例代码。 假设我们要对一个简单的模块进行测试,这个模块包含一个加法器,输入两个数,输出它们的和。我们需要对这个模块进行功能测试、时序测试和容错测试。 1. 功能测试:我们需要对加法器进行各种组合的测试,以测试加法器的计算能力。这些测试可以通过生成随机数,并将其输入到加法器中进行计算,然后比对加法器的输出结果和预期结果是否一致。测试用例代码示例如下: ``` task test_adder; int a, b, c, expected; initial begin // test case 1: a=0, b=0 a = 0; b = 0; expected = 0; c = adder(a, b); if (c !== expected) $error("Test case 1 failed"); // test case 2: a=1, b=2 a = 1; b = 2; expected = 3; c = adder(a, b); if (c !== expected) $error("Test case 2 failed"); // test case 3: a=-2, b=3 a = -2; b = 3; expected = 1; c = adder(a, b); if (c !== expected) $error("Test case 3 failed"); // more test cases ... end endtask ``` 2. 时序测试:我们需要测试加法器在不同的时序条件下的计算能力。这些测试可以通过设置不同的时钟频率和时序延迟,并对加法器进行计算和比对输出结果。测试用例代码示例如下: ``` task test_adder_timing; int a, b, c, expected; initial begin // test case 1: 100 MHz clock, 2 ns delay $timescale(1ns/100ps); @(posedge clk); a = 0; b = 0; expected = 0; c = adder(a, b); if (c !== expected) $error("Test case 1 failed"); // test case 2: 200 MHz clock, 1 ns delay $timescale(1ns/100ps); @(posedge clk); a = 1; b = 2; expected = 3; c = adder(a, b); if (c !== expected) $error("Test case 2 failed"); // test case 3: 300 MHz clock, 0.5 ns delay $timescale(1ns/100ps); @(posedge clk); a = -2; b = 3; expected = 1; c = adder(a, b); if (c !== expected) $error("Test case 3 failed"); // more test cases ... end endtask ``` 3. 容错测试:我们需要测试加法器在不同的异常情况下的容错能力。这些测试可以通过模拟不同的异常情况,如电压波动、温度变化和信号干扰等,对加法器进行计算和比对输出结果。测试用例代码示例如下: ``` task test_adder_fault; int a, b, c, expected; initial begin // test case 1: voltage fluctuation a = 0; b = 0; expected = 0; // simulate voltage fluctuation vdd = 1.0; @(posedge clk); vdd = 0.9; @(posedge clk); vdd = 1.1; @(posedge clk); c = adder(a, b); if (c !== expected) $error("Test case 1 failed"); // test case 2: temperature change a = 1; b = 2; expected = 3; // simulate temperature change temp = 25; @(posedge clk); temp = 30; @(posedge clk); temp = 20; @(posedge clk); c = adder(a, b); if (c !== expected) $error("Test case 2 failed"); // test case 3: signal interference a = -2; b = 3; expected = 1; // simulate signal interference @(posedge clk); @(posedge clk); @(posedge clk); @(posedge clk); @(posedge clk); @(posedge clk); @(posedge clk); @(posedge clk); c = adder(a, b); if (c !== expected) $error("Test case 3 failed"); // more test cases ... end endtask ``` 以上是一个简单的 case 抽取测试用例代码生成的示例。实际的 case 抽取测试用例设计需要根据具体的验证需求和测试目标进行细化和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值