q发数、QPS、^均响应时间三者之间关p?/p>
<!--[if !supportLists]-->二?nbsp; <!--[endif]-->限时试?/p>
q记得我在初U篇中给出的例子吗,那个求^Ҏ(gu)的函数有BugQ是个死循环Q?/p>
如果试的时候遇到死循环Q你的脸上绝对不?x)露出笑宏V因此,对于那些逻辑很复杂,循环嵌套比较qE序Q很有可能出现死循环Q因此一定要采取一些预防措施。限时测试是一个很好的解决Ҏ(gu)。我们给q些试函数讑֮一个执行时_(d)过?jin)这个时_(d)他们׃(x)被系l强行终止,q且pȝq会(x)向你汇报该函数结束的原因是因Ӟq样你就可以发现q些Bug?jin)。要实现q一功能Q只需要给@Test标注加一个参数即可,代码如下Q?/p>
Timeout参数表明?jin)你要设定的旉Q单位ؓ(f)毫秒Q因?000׃?U?/p>
<!--[if !supportLists]-->三?nbsp; <!--[endif]-->试异常
JAVA中的异常处理也是一个重点,因此你经怼(x)~写一些需要抛出异常的函数。那么,如果你觉得一个函数应该抛出异常,但是它没抛出Q这不Bug呢?q当然是BugQƈJUnit也考虑C(jin)q一点,来帮助我们找到这UBug。例如,我们写的计算器类有除法功能,如果除数是一?Q那么必然要抛出“?异常”。因此,我们很有必要对这些进行测试。代码如下:(x)
如上qC码所C,我们需要用@Test标注的expected属性,我们要(g)验的异常传递给他,q样JUnit框架p自动帮我们检是否抛Z(jin)我们指定的异常?/pre><!--[if !supportLists]--><!--[endif]-->四?nbsp; Runner (q行?
大家有没有想q这个问题,当你把测试代码提交给JUnit框架后,框架如何来运行你的代码呢Q答案就是——Runner。在JUnit中有很多个RunnerQ他们负责调用你的测试代码,每一个Runner都有各自的特D功能,你要Ҏ(gu)需要选择不同的Runner来运行你的测试代码。可能你?x)觉得奇怪,前面我们写了(jin)那么多测试,q没有明指定一个Runner啊?q是因ؓ(f)JUnit中有一个默认RunnerQ如果你没有指定Q那么系l自动用默认Runner来运行你的代码。换句话_(d)下面两段代码含义是完全一L(fng)Q?/p>
import org.junit.internal.runners.TestClassRunner;
import org.junit.runner.RunWith;
![]()
//使用?jin)系l默认的TestClassRunnerQ与下面代码完全一?br>
public class CalculatorTest ...{
...
}
![]()
![]()
@RunWith(TestClassRunner.class)
public class CalculatorTest ...{
...
}
从上qC子可以看出,要想指定一个RunnerQ需要用@RunWith标注Qƈ且把你所指定的Runner作ؓ(f)参数传递给它。另外一个要注意的是Q@RunWith是用来修饰类的,而不是用来修饰函数的。只要对一个类指定?jin)RunnerQ那么这个类中的所有函数都被这个Runner来调用。最后,不要忘了(jin)包含相应的Package哦,上面的例子对q一点写的很清楚?jin)。接下来Q我?x)向你们展示其他Runner的特有功能?/p>
<!--[if !supportLists]-->五?nbsp; <!--[endif]-->参数化测试?/p>
你可能遇到过q样的函敎ͼ它的参数有许多特D|或者说他的参数分ؓ(f)很多个区域。比如,一个对考试分数q行评h(hun)的函敎ͼq回值分别ؓ(f)“优秀Q良好,一般,?qing)格Q不?qing)?#8221;Q因此你在编写测试的时候,臛_要写5个测试,把这5中情况都包含?jin),q确实是一件很ȝ(ch)的事情。我们还使用我们先前的例子,试一?#8220;计算一个数的^?#8221;q个函数Q暂且分三类Q正数?、负数。测试代码如下:(x)
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
![]()
public class AdvancedTest ...{
![]()
private static Calculator calculator Q?nbsp;new Calculator();
![]()
@Before
public void clearCalculator() ...{
calculator.clear();
}
![]()
@Test
public void square1() ...{
calculator.square(2);
assertEquals(4, calculator.getResult());
}
![]()
@Test
public void square2() ...{
calculator.square(0);
assertEquals(0, calculator.getResult());
}
![]()
@Test
public void square3() ...{
calculator.square(-3);
assertEquals(9, calculator.getResult());
}
![]()
}
Z(jin)化类似的试QJUnit4提出?#8220;参数化测?#8221;的概念,只写一个测试函敎ͼ把这若干U情况作为参C递进去,一ơ性的完成试。代码如下:(x)
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
![]()
import java.util.Arrays;
import java.util.Collection;
![]()
@RunWith(Parameterized.class)
public class SquareTest ...{
![]()
private static Calculator calculator = new Calculator();
private int param;
private int result;
![]()
@Parameters
public static Collection data() ...{
return Arrays.asList(new Object[][]...{
...{2, 4},
...{0, 0},
...{Q?, 9},
});
}
![]()
![]()
//构造函敎ͼ对变量进行初始化
public SquareTest(int param, int result) ...{
this.param = param;
this.result = result;
}
![]()
@Test
public void square() ...{
calculator.square(param);
assertEquals(result, calculator.getResult());
}
![]()
}
下面我们对上qC码进行分析。首先,你要U测试专门生成一个新的类Q而不能与其他试q同一个类Q此例中我们定义?jin)一个SquareTestcR然后,
你要个类指定一个RunnerQ而不能用默认的Runner?jin),因?f)Ҏ(gu)的功能要用特D的Runner嘛。@RunWith(Parameterized.class)q条语句是个类?br>定了(jin)一个ParameterizedRunner。第二步Q定义一个待试的类Qƈ且定义两个变量,一个用于存攑֏敎ͼ一个用于存放期待的l果。接下来Q定义测试数据的集合Q?br>也就是上q的data()Ҏ(gu)Q该Ҏ(gu)可以L命名Q但是必M用@Parameters标注q行修饰。这个方法的框架׃予解释了(jin)Q大家只需要注意其中的数据Q是一个二
l数l,数据两两一l,每组中的q两个数据,一个是参数Q一个是你预期的l果。比如我们的W一l{2, 4}Q?是参数Q?是预期的结果。这两个数据的顺序无所
谓,谁前谁后都可以。之后是构造函敎ͼ其功能就是对先前定义的两个参数进行初始化。在q里你可要注意一下参数的序?jin),要和上面的数据集合的序保持一致?br>如果前面的顺序是{参数Q期待的l果}Q那么你构造函数的序也要?#8220;构造函?参数Q?期待的结?”Q反之亦然。最后就是写一个简单的试例了(jin)Q和前面介绍
q的写法完全一P在此׃多说?/pre><!--[if !supportLists]-->六?nbsp; <!--[endif]-->打包试?/p>
通过前面的介l我们可以感觉到Q在一个项目中Q只写一个测试类是不可能的,我们?x)写出很多很多个试cR可是这些测试类必须一个一个的执行Q也是比较麻?ch)的事情。鉴于此QJUnit为我们提供了(jin)打包试的功能,所有需要运行的试c集中v来,一ơ性的q行完毕Q大大的方便?jin)我们的试工作。具体代码如下:(x)
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses(...{
CalculatorTest.class,
SquareTest.class
})
public class AllCalculatorTests ...{
}
大家可以看到Q这个功能也需要用一个特D的RunnerQ因此我们需要向@RunWith标注传递一个参数Suite.class。同Ӟ我们q需要另外一个标注@Suite.SuiteClassesQ来表明q个cL一个打包测试类。我们把需要打包的cM为参C递给该标注就可以?jin)。有?jin)这两个标注之后Q就已经完整的表达了(jin)所有的含义Q因此下面的cdl无关紧要,随便起一个类名,内容全部为空既可?/p>
]]>