Junit4中怎样随心所欲mercy的执行Test

用JUnit4进行单元测试 - 飘零的云 - ITeye博客
博客分类:
用Junit进行单元测试很方便,尤其是Junit4引入了很多Annotation注解以后。看测试的示例:
待测试类:
public class Calculator {
public int add(int a, int b) {
return a +
public int minus(int a, int b) {
return a -
public int square(int n) {
return n *
//Bug : 死循环
public void squareRoot(int n) {
public int multiply(int a, int b) {
return a *
public int divide(int a, int b) throws Exception {
if (0 == b) {
throw new Exception("除数不能为零");
return a /
单元测试类:
import org.junit.A
import org.junit.AfterC
import org.junit.A
import org.junit.B
import org.junit.BeforeC
import org.junit.I
import org.junit.T
public class CalculatorTest {
private Calculator cal = new Calculator();
@BeforeClass // 注意,这里必须是static...因为方法将在类被装载的时候就被调用(那时候还没创建实例)
public static void before()
System.out.println("global");
@AfterClass
public static void after() {
System.out.println("global destroy");
public void setUp() throws Exception {
System.out.println("一个测试开始。。");
public void tearDown() throws Exception {
System.out.println("一个测试结束");
public void testAdd() {
int result = cal.add(1, 2);
Assert.assertEquals(3, result);
public void testMinus() {
int result = cal.minus(5, 2);
Assert.assertEquals(3, result);
public void testMultiply() {
int result = cal.multiply(4, 2);
Assert.assertEquals(8, result);
@Test(timeout = 1000) // 单位为毫秒
public void testSquareRoot() {
cal.squareRoot(4);
@Test(expected = Exception.class)
public void testDivide() throws Exception {
System.out.println("teddd");
cal.divide(4, 0);// 很简单的办法.......
// public void testDivide() {
int result = 0;
result = cal.divide(10, 5);
} catch (Exception e) {
e.printStackTrace();
Assert.fail();// 如果这行没有执行。说明这部分正确。
Assert.assertEquals(2, result);
在Eclipse里Run As -& JUnit Test,运行测试类,Eclipse的JUnit的View显示如:
可以看到,CalculatorTest类中总共有5个测试用例,ignore了一个,3个测试用例通过,testSquareRoot测试不通过(因为超时),所以整个的测试结果飘红了。同时,控制台的输出结果为:
一个测试开始。。
一个测试结束
一个测试开始。。
一个测试结束
一个测试开始。。
一个测试结束
一个测试开始。。
一个测试结束
global destroy
各种注解的说明:
表明该方法是一个测试方法
@BeforeClass 和 @AfterClass:
测试用例初始化时执行 @BeforeClass方法,当所有测试执行完毕之后,执行@AfterClass进行收尾工作。标注、@BeforeClass 和 @AfterClass的方法必须是static的,因为方法将在类被装载的时候就被调用,那时候还没创建测试对象实例。
@Before: 使用了该元数据的方法在每个测试方法执行之前都要执行一次。
@After: 使用了该元数据的方法在每个测试方法执行之后要执行一次。
@Test(expected=*.class) :通过@Test元数据中的expected属性验证是否抛出期望的异常,expected属性的值是一个异常的类型,如果抛出了期望的异常,则测试通过,否则不通过。
@Test(timeout=xxx):该元数据传入了一个时间(毫秒)给测试方法,如果测试方法在制定的时间之内没有运行完,则测试也失败。
@Ignore: 该元数据标记的测试方法在测试中会被忽略。同时可以为该标签传递一个String的参数,来表明为什么会忽略这个测试方法。比如:@lgnore("该方法还没有实现"),在执行的时候,仅会报告该方法没有实现,而不会运行测试方法。
在test方法内除了使用Assert的assertEquals()方法外,还能使用assertFalse()、assertTrue()、assertNull()、assertNotNull()、assertSame()、assertNotSame()等断言函数。而且如果使用的是Junit4,结合Hamcrest,使用
assertThat([value], [matcher statement])方法可以实现更灵活的断言判断(前提是引入hamcrest的jar包)。
// is匹配符表明如果前面待测的object等于后面给出的object,则测试通过
assertThat( testedObj, is( object) );
// containsString匹配符表明如果测试的字符串包含指定的子字符串则测试通过
assertThat( testedString, containsString( "developerWorks" ) );
// greaterThan匹配符表明如果所测试的数值testedNumber大于16.0则测试通过
assertThat( testedNumber, greaterThan(16.0) );
// closeTo匹配符表明如果所测试的浮点型数testedDouble在20.0±0.5范围之内则测试通过
assertThat( testedDouble, closeTo( 20.0, 0.5 ) );
//hasItem匹配符表明被测的迭代对象含有元素element项则测试通过assertThat(iterableObject, hasItem (element));
更多更详细的Hamcrest提供的断言判断参考:
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////分割线
上面的Caculator待测试类里,现在我如果想给square方法多弄几个测试用例,按照上面的方法,我应该写好几个@Test方法来测试,或者每次测完再改一下输入的值和期望得到的值,好麻烦。JUnit提供如下的测试:
import java.util.A
import java.util.C
import org.junit.A
import org.junit.T
import org.junit.runner.RunW
import org.junit.runners.P
import org.junit.runners.Parameterized.P
@RunWith(Parameterized.class)
public class CalculatorTest2{
private Calculator cal = new Calculator();
//构造函数,对变量进行初始化
//定义一个待测试的类,并且定义两个变量,一个用于存放参数,一个用于存放期待的结果。
public CalculatorTest2(int param, int result) {
this.param =
this.result =
@Parameters
public static Collection data(){
return Arrays.asList(new Object[][]{
public void squareTest() {
int temp = cal.square(param);
Assert.assertEquals(result, temp);
Eclipse里JUnit的运行结果显示为:
测试通过了,CalculatorTest2类里的parameter是每次的测试输入,result就是测试的结果。所有的测试输入和期望结果都在@Parameters标注的data函数的返回的Collection集合里,2的期望得到的平方结果值是4,0期望得到0,-3期望得到9。
把测试代码提交给JUnit框架后,框架如何来运行代码呢?答案就是——Runner。在JUnit中有很多个 Runner,他们负责调用测试代码,每一个Runner都有各自的特殊功能,要根据需要选择不同的Runner来运行测试代码。JUnit中有一个默认Runner,如果没有指定,那么系统自动使用默认 Runner来运行你的代码。这里参数化测试就没有再用默认的Runner了。
再看看打包测试测例子:
import org.junit.runner.RunW
import org.junit.runners.S
* 大家可以看到,这个功能也需要使用一个特殊的Runner,
* 因此我们需要向@RunWith标注传递一个参数Suite.class。
* 同时,我们还需要另外一个标注@Suite.SuiteClasses,
* 来表明这个类是一个打包测试类。我们把需要打包的类作为参数传递给该标注就可以了。
* 有了这两个标注之后,就已经完整的表达了所有的含义,因此下面的类已经无关紧要,
* 随便起一个类名,内容全部为空既可
@RunWith(Suite.class)
@Suite.SuiteClasses({ CalculatorTest.class, CalculatorTest2.class })
public class AllCalculatorTests {
这个测试类包含了上面的CalculatorTest.class和CalculatorTest2.class里面所有的测试函数,它的目的就是进行打包所有的测试。
浏览 33480
tonlion2046
浏览: 295459 次
来自: 杭州
支持分布式吗
qingchenyuji 写道您好,
看了您的博文,想向您请 ...JUnit4用法详解
测试驱动开发,它是敏捷开发的最重要的部分。方法主要是先根据客户的需求编写测试程序,然后再编码使其通过测试。在敏捷开发实施中,开发人员主要从两个方面去理解测试驱动开发。
a)在测试的辅助下,快速实现客户需求的功能。通过编写测试用例,对客户需求的功能进行分解,并进行系统设计。我们发现从使用角度对代码的设计通常更符合后期开发的需求。可测试的要求,对代码的内聚性的提高和复用都非常有益。
b)在测试的保护下,不断重构代码,提高代码的重用性,从而提高软件产品的质量。可见测试驱动开发实施的好坏确实极大的影响软件产品的质量,贯穿了软件开发的始终。
在测试驱动开发中,为了保证测试的稳定性,被测代码接口的稳定性是非常重要的。否则,变化的成本就会急剧的上升。所以,自动化测试将会要求您的设计依赖于接口,而不是具体的类。进而推动设计人员重视接口的设计,体现系统的可扩展性和抗变性。
JUnit4的用法介绍
Java 语言现在支持泛型、枚举、可变长度参数列表和注释,这些特性为可重用的框架设计带来了新的可能。
JUnit4利用 Java 5 的新特性(尤其是注释)的优势,使得单元测试比起用最初的 JUnit 来说更加简单。
测试方法 @Test
以前所有版本的 JUnit 都使用命名约定和反射来定位测试。例如,下面的代码测试 1 + 1 等于 2:
import&junit.framework.TestC
public&class&AdditionTest&extends&TestCase&{
private&int&x&=&<span STYLE="color: #;
private&int&y&=&<span STYLE="color: #;
public&void&testAddition()&{
int&z&=&x&+&y;
assertEquals(<span STYLE="color: #,&z);
而在 JUnit4 中,测试是由 @Test 注释来识别的,如下所示:
import&org.junit.T
import&junit.framework.TestC
public&class&AdditionTest&{
private&int&x&=&<span STYLE="color: #;
private&int&y&=&<span STYLE="color: #;
public&void&testAddition()&{
int&z&=&x&+&y;
assertEquals(<span STYLE="color: #,&z);
使用注释来识别测试方法的优点是不再需要将所有的方法命名为
testAddition()、testXXX()的形式等等。
例如,下面的方法也可以工作:
import&org.junit.T
import&junit.framework.TestC
public&class&AdditionTest&{
private&int&x&=&<span STYLE="color: #;
private&int&y&=&<span STYLE="color: #;
public&void&addition()&{
int&z&=&x&+&y;
assertEquals(<span STYLE="color: #,&z);
使用这种方法的好处是:
a)允许我们遵循最适合的应用程序的命名约定。
我们可以将测试方法使用与被测试的类相同的名称(由开发组规范约定)。例如,LoginAction.login() 由
LoginActionTest.login()方法测试、LoginAction.check()由LoginActionTest.check()方
法测试等等。
b)使用JUnit4后,测试用例类可以不继承TestCase类,所以我们也就可以扩展被测试类了。
这种方法使得测试受保护的方法非常容易,我们只要将测试用例类继承被测试类,就可以测试受保护方法了。
@Before(SetUp)
JUnit 3 测试运行程序会在运行每个测试之前自动调用 setUp() 方法。该方法一般会初始化字段、准备数据等等。例如下面的
setUp() 方法,用于设定要加载的路由文件:
public&void&setUp()&{
//&加载此测试用例的servicerouting配置文件
ServiceRouting.loadConfig("com/demo/servicerouting.conf");
在 JUnit4 中,我们仍然可以在每个测试方法运行之前初始化字段或准备数据。然而,完成这些操作的方法不再需要叫做
setUp(),只要用 @Before 注释来指示该方法即可,如下所示:
public&void&initialize()&{
//&加载此测试用例的servicerouting配置文件
ServiceRouting.loadConfig("com/demo/servicerouting.conf");
JUnit4允许我们使用 @Before 来注释多个方法,这些方法都在每个测试之前运行:
public&void&initialize()&{
//&加载此测试用例的servicerouting配置文件
ServiceRouting.loadConfig("com/demo/servicerouting.conf");
public&void&prepareRetData()&{
@After(TearDown)
清除方法与初始化方法类似。在 JUnit3 中,我们要将方法命名为 tearDown()
才可以实现清除方法,但在JUnit4中,只要给方法添加@After标注即可。
&&&&@After
public&static&void&clearContext()&{
ActionContext.getContext().put(StrutsStatics.HTTP_REQUEST,&null);
ActionContext.setContext(null);
测试方法结束后清除为此测试用例准备的一些数据。
与 @Before 一样,也可以用 @After 来注释多个清除方法,这些方法都在每个测试之后运行。
最后,我们不再需要显式调用在超类中的初始化和清除方法,只要它们不被覆盖,测试运行程序将根据需要自动为您调用这些方法。
超类中的 @Before 方法在子类中的 @Before 方法之前被调用(这反映了构造函数调用的顺序)。
@After 方法以反方向运行:子类中的方法在超类中的方法之前被调用。否则,多个 @Before 或 @After
方法的相对顺序就得不到保证。
@Before和@After小结
假设测试类中有如下方法定义:
public&void&init(){}
public&void&destroy(){}
则Before、After方法的执行流程如图所示:
测试驱动开发,它是敏捷开发的最重要的部分。方法主要是先根据客户的需求编写测试程序,然后再编码使其通过测试。在敏捷开发实施中,开发人员主要从两个方面去理解测试驱动开发。
a)在测试的辅助下,快速实现客户需求的功能。通过编写测试用例,对客户需求的功能进行分解,并进行系统设计。我们发现从使用角度对代码的设计通常更符合后期开发的需求。可测试的要求,对代码的内聚性的提高和复用都非常有益。
b)在测试的保护下,不断重构代码,提高代码的重用性,从而提高软件产品的质量。可见测试驱动开发实施的好坏确实极大的影响软件产品的质量,贯穿了软件开发的始终。
在测试驱动开发中,为了保证测试的稳定性,被测代码接口的稳定性是非常重要的。否则,变化的成本就会急剧的上升。所以,自动化测试将会要求您的设计依赖于接口,而不是具体的类。进而推动设计人员重视接口的设计,体现系统的可扩展性和抗变性。
JUnit4的用法介绍
Java 语言现在支持泛型、枚举、可变长度参数列表和注释,这些特性为可重用的框架设计带来了新的可能。
JUnit4利用 Java 5 的新特性(尤其是注释)的优势,使得单元测试比起用最初的 JUnit 来说更加简单。
测试方法 @Test
以前所有版本的 JUnit 都使用命名约定和反射来定位测试。例如,下面的代码测试 1 + 1 等于 2:
import&junit.framework.TestC
public&class&AdditionTest&extends&TestCase&{
private&int&x&=&<span STYLE="color: #;
private&int&y&=&<span STYLE="color: #;
public&void&testAddition()&{
int&z&=&x&+&y;
assertEquals(<span STYLE="color: #,&z);
而在 JUnit4 中,测试是由 @Test 注释来识别的,如下所示:
import&org.junit.T
import&junit.framework.TestC
public&class&AdditionTest&{
private&int&x&=&<span STYLE="color: #;
private&int&y&=&<span STYLE="color: #;
public&void&testAddition()&{
int&z&=&x&+&y;
assertEquals(<span STYLE="color: #,&z);
使用注释来识别测试方法的优点是不再需要将所有的方法命名为
testAddition()、testXXX()的形式等等。
例如,下面的方法也可以工作:
import&org.junit.T
import&junit.framework.TestC
public&class&AdditionTest&{
private&int&x&=&<span STYLE="color: #;
private&int&y&=&<span STYLE="color: #;
public&void&addition()&{
int&z&=&x&+&y;
assertEquals(<span STYLE="color: #,&z);
使用这种方法的好处是:
a)允许我们遵循最适合的应用程序的命名约定。
我们可以将测试方法使用与被测试的类相同的名称(由开发组规范约定)。例如,LoginAction.login() 由
LoginActionTest.login()方法测试、LoginAction.check()由LoginActionTest.check()方
法测试等等。
b)使用JUnit4后,测试用例类可以不继承TestCase类,所以我们也就可以扩展被测试类了。
这种方法使得测试受保护的方法非常容易,我们只要将测试用例类继承被测试类,就可以测试受保护方法了。
@Before(SetUp)
JUnit 3 测试运行程序会在运行每个测试之前自动调用 setUp() 方法。该方法一般会初始化字段、准备数据等等。例如下面的
setUp() 方法,用于设定要加载的路由文件:
public&void&setUp()&{
//&加载此测试用例的servicerouting配置文件
ServiceRouting.loadConfig("com/demo/servicerouting.conf");
在 JUnit4 中,我们仍然可以在每个测试方法运行之前初始化字段或准备数据。然而,完成这些操作的方法不再需要叫做
setUp(),只要用 @Before 注释来指示该方法即可,如下所示:
public&void&initialize()&{
//&加载此测试用例的servicerouting配置文件
ServiceRouting.loadConfig("com/demo/servicerouting.conf");
JUnit4允许我们使用 @Before 来注释多个方法,这些方法都在每个测试之前运行:
public&void&initialize()&{
//&加载此测试用例的servicerouting配置文件
ServiceRouting.loadConfig("com/demo/servicerouting.conf");
public&void&prepareRetData()&{
@After(TearDown)
清除方法与初始化方法类似。在 JUnit3 中,我们要将方法命名为 tearDown()
才可以实现清除方法,但在JUnit4中,只要给方法添加@After标注即可。
public&static&void&clearContext()&{
ActionContext.getContext().put(StrutsStatics.HTTP_REQUEST,&null);
ActionContext.setContext(null);
测试方法结束后清除为此测试用例准备的一些数据。
与 @Before 一样,也可以用 @After 来注释多个清除方法,这些方法都在每个测试之后运行。
最后,我们不再需要显式调用在超类中的初始化和清除方法,只要它们不被覆盖,测试运行程序将根据需要自动为您调用这些方法。
超类中的 @Before 方法在子类中的 @Before 方法之前被调用(这反映了构造函数调用的顺序)。
@After 方法以反方向运行:子类中的方法在超类中的方法之前被调用。否则,多个 @Before 或 @After
方法的相对顺序就得不到保证。
@Before和@After小结
假设测试类中有如下方法定义:
public&void&init(){}
public&void&destroy(){}
则Before、After方法的执行流程如图所示:
这种方法有明显的缺陷,如果要初始化的是数据库的链接,或者是一个大的对象的话,而这些资源恰恰是整个测试用例类可以共用的,每次都去申请,确实是种浪费。所以JUnit4引入了@BeforeClass和@AfterClass。
@BeforeClass和@AfterClass
JUnit4 也引入了一个 JUnit3 中没有的新特性:类范围的 setUp() 和 tearDown() 方法。任何用
@BeforeClass 注释的方法都将在该类中的测试方法运行之前刚好运行一次,而任何用 @AfterClass
注释的方法都将在该类中的所有测试都运行之后刚好运行一次。
例如,假设类中的每个测试都使用一个数据库连接、一个非常大的数据结构,或者申请其他一些资源。不要在每个测试之前都重新创建它,您可以创建它一次,用完后将其销毁清除。该方法将使得有些测试案例运行起来快得多。
注意:被注释为 BeforeClass和AfterClass
的方法必须为static方法。
用法如下:
&&&&@BeforeClass
public&static&void&classInit()&{
Map&callRet&=&new&HashMap();
List&ErrorCodeMessageBean&&list&=&new&ArrayList&ErrorCodeMessageBean&();
list.add(createMsgBean("TDE0001",&"第一个错误消息"));
list.add(createMsgBean("TDP9999",&"格式化{0}{1}"));
list.add(createMsgBean("TDE1000~TDF0001",&"区间错误消息"));
list.add(createMsgBean("TDG0001~",&"有下限的区间错误消息"));
list.add(createMsgBean("~TDD0001",&"有上限的区间错误消息"));
list.add(createMsgBean("~",&"默认的消息"));
callRet.put(ErrorCodeMessageBean.codeMsgBeanKey,&list);
ServiceCall.expectLastCallReturn(callRet);
public&void&oneTestMethod()&{
@AfterClass
public&static&void&classDestroy()&{
ServiceCall.expectLastCallReturn(null);
这个特定虽然很好,但是一定要小心对待这个特性。它有可能会违反测试的独立性,并引入非预期的混乱。如果一个测试在某种程度上改变了
@BeforeClass
所初始化的一个对象,那么它有可能会影响其他测试的结果。也就是说,由BeforeClass申请或创建的资源,如果是整个测试用例类共享的,那么尽量不
要让其中任何一个测试方法改变那些共享的资源,这样可能对其他测试方法有影响。它有可能在测试套件中引入顺序依赖,并隐藏
BeforeClass和AfterClass的执行流程如下:
这种方法有明显的缺陷,如果要初始化的是数据库的链接,或者是一个大的对象的话,而这些资源恰恰是整个测试用例类可以共用的,每次都去申请,确实是种浪费。所以JUnit4引入了@BeforeClass和@AfterClass。
@BeforeClass和@AfterClass
JUnit4 也引入了一个 JUnit3 中没有的新特性:类范围的 setUp() 和 tearDown() 方法。任何用
@BeforeClass 注释的方法都将在该类中的测试方法运行之前刚好运行一次,而任何用 @AfterClass
注释的方法都将在该类中的所有测试都运行之后刚好运行一次。
例如,假设类中的每个测试都使用一个数据库连接、一个非常大的数据结构,或者申请其他一些资源。不要在每个测试之前都重新创建它,您可以创建它一次,用完后将其销毁清除。该方法将使得有些测试案例运行起来快得多。
注意:被注释为 BeforeClass和AfterClass
的方法必须为static方法。
用法如下:
&&&@BeforeClass
public&static&void&classInit()&{
Map&callRet&=&new&HashMap();
List&ErrorCodeMessageBean&&list&=&new&ArrayList&ErrorCodeMessageBean&();
list.add(createMsgBean("TDE0001",&"第一个错误消息"));
list.add(createMsgBean("TDP9999",&"格式化{0}{1}"));
list.add(createMsgBean("TDE1000~TDF0001",&"区间错误消息"));
list.add(createMsgBean("TDG0001~",&"有下限的区间错误消息"));
list.add(createMsgBean("~TDD0001",&"有上限的区间错误消息"));
list.add(createMsgBean("~",&"默认的消息"));
callRet.put(ErrorCodeMessageBean.codeMsgBeanKey,&list);
ServiceCall.expectLastCallReturn(callRet);
public&void&oneTestMethod()&{
@AfterClass
public&static&void&classDestroy()&{
ServiceCall.expectLastCallReturn(null);
这个特定虽然很好,但是一定要小心对待这个特性。它有可能会违反测试的独立性,并引入非预期的混乱。如果一个测试在某种程度上改变了
@BeforeClass
所初始化的一个对象,那么它有可能会影响其他测试的结果。也就是说,由BeforeClass申请或创建的资源,如果是整个测试用例类共享的,那么尽量不
要让其中任何一个测试方法改变那些共享的资源,这样可能对其他测试方法有影响。它有可能在测试套件中引入顺序依赖,并隐藏
BeforeClass和AfterClass的执行流程如下:
测试异常@Test(expected=XXXException.class)
异常测试是 JUnit4 中的最大改进。旧式的异常测试是在抛出异常的代码中放入 try 块,然后在 try 块的末尾加入一个
fail() 语句。
例如,该方法测试被零除抛出一个 ArithmeticException:
public&void&testDivisionByZero()&{
int&n&=&<span STYLE="color: #&/&<span STYLE="color: #;
fail("Divided&by&zero!");
catch&(ArithmeticException&success)&{
assertNotNull(success.getMessage());
该方法不仅难看,而且写起来也繁琐。在 JUnit 4
中,我们现在可以编写抛出异常的代码,并使用注释来声明该异常是预期的:
&&&&@Test(expected&=&BusinessException.class)
public&void&testExecuteNameEmpty()&throws&Exception&{
BookList&bListAction&=&new&BookList();
bListAction.setName("");
bListAction.execute();
附被测试代码(如果输入name为empty,则抛出BusinessException,若name不为"liming",则抛出MessageException异常):
&&&&@Override
public&String&execute()&throws&Exception&{
if&(StringUtils.isEmpty(name))&{
throw&new&BusinessException("~",&"name&cant't&empty.");
if&(!StringUtils.equals("liming",&name.trim()))&{
throw&new&MessageException(name&+&"&have&no&limits.");
Map&ret&=&serviceCall.call(JMockService.queryDtlInfo,&null);
orderId&=&(String)&ret.get("OrderId");
dataList&=&(List)&ret.get("Data");
return&SUCCESS;
参数化测试
为了保证单元测试的严谨性,我们经常要模拟很多种输入参数,来确定我们的功能代码是可以正常工作的,为此我们编写大量的单元测试方法。可是这些测试方法都是大同小异:代码结构都是相同的,不同的仅仅是测试数据和期望输出值。
的参数化测试方法给我们提供了更好的方法,将测试方法中相同的代码结构提取出来,提高代码的重用度,减少复制粘贴代码的痛苦。
例如下面的功能代码(格式化字符串,将驼峰规则的字符串以"_"分隔):
public&class&WordDealUtil&{
public&static&String&wordFormat4DB(String&name)&{
if&(name&==&null)&{
return&null;
Pattern&p&=&<pile("[A-Z]");
Matcher&m&=&p.matcher(name);
StringBuffer&sb&=&new&StringBuffer();
while&(m.find())&{
if&(m.start()&!=&<span STYLE="color: #)&{
m.appendReplacement(sb,&("_"&+&m.group()).toLowerCase());
return&m.appendTail(sb).toString().toLowerCase();
没有使用参数化的测试用例代码:
public&class&WordDealUtilTest&{
public&void&wordFormat4DBNull()&{
String&target&=&null;
String&result&=&WordDealUtil.wordFormat4DB(target);
assertNull(result);
public&void&wordFormat4DBEmpty()&{
String&target&=&"";
String&result&=&WordDealUtil.wordFormat4DB(target);
assertEquals("",&result);
public&void&wordFormat4DBegin()&{
String&target&=&"EmployeeInfo";
String&result&=&WordDealUtil.wordFormat4DB(target);
assertEquals("employee_info",&result);
public&void&wordFormat4DBEnd()&{
String&target&=&"employeeInfoA";
String&result&=&WordDealUtil.wordFormat4DB(target);
assertEquals("employee_info_a",&result);
public&void&wordFormat4DBTogether()&{
String&target&=&"employeeAInfo";
String&result&=&WordDealUtil.wordFormat4DB(target);
assertEquals("employee_a_info",&result);
看以上测试用例代码,结构相似,只是输入值与期望输出不同而已,但我们要拷贝很多代码。
使用参数化的测试用例代码:
@SuppressWarnings("unchecked")
@RunWith(Parameterized.class)
public&class&WordDealUtilTestWithParam&{
private&String&
private&String&
@Parameters
public&static&Collection&words()&{
return&Arrays.asList(new&Object[][]&{
{&"employee_info",&"employeeInfo"&},&&//&测试一般的处理情况
{&null,&null&},&&&&&&&&&&&&&&&&&&&&&&&&&//&测试&null&时的处理情况
{&"",&""&},&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//&测试空字符串时的处理情况
{&"employee_info",&"EmployeeInfo"&},&&&&//&测试当首字母大写时的情况
{&"employee_info_a",&"employeeInfoA"&},&//&测试当尾字母为大写时的情况
{&"employee_a_info",&"employeeAInfo"&}&&//&测试多个相连字母大写时的情况
public&WordDealUtilTestWithParam(String&expected,&String&target)&{
this.expected&=&
this.target&=&
public&void&wordFormat4DB()&{
Assert.assertEquals(expected,&WordDealUtil.wordFormat4DB(target));
很明显,代码简单且很清晰了。在静态方法 words
中,我们使用二维数组来构建测试所需要的参数列表,其中每个数组中的元素的放置顺序并没有什么要求,只要和构造函数中的顺序保持一致就可以了。现在如果再
增加一种测试情况,只需要在静态方法 words 中添加相应的数组即可,不再需要复制粘贴出一个新的方法出来了。
这种参数化的测试用例写法,很适用于一些共用的功能方法。
测试异常@Test(expected=XXXException.class)
异常测试是 JUnit4 中的最大改进。旧式的异常测试是在抛出异常的代码中放入 try 块,然后在 try 块的末尾加入一个
fail() 语句。
例如,该方法测试被零除抛出一个 ArithmeticException:
public&void&testDivisionByZero()&{
int&n&=&<span STYLE="color: #&/&<span STYLE="color: #;
fail("Divided&by&zero!");
catch&(ArithmeticException&success)&{
assertNotNull(success.getMessage());
该方法不仅难看,而且写起来也繁琐。在 JUnit 4
中,我们现在可以编写抛出异常的代码,并使用注释来声明该异常是预期的:
&&&@Test(expected&=&BusinessException.class)
public&void&testExecuteNameEmpty()&throws&Exception&{
BookList&bListAction&=&new&BookList();
bListAction.setName("");
bListAction.execute();
附被测试代码(如果输入name为empty,则抛出BusinessException,若name不为"liming",则抛出MessageException异常):
&&&&@Override
public&String&execute()&throws&Exception&{
if&(StringUtils.isEmpty(name))&{
throw&new&BusinessException("~",&"name&cant't&empty.");
if&(!StringUtils.equals("liming",&name.trim()))&{
throw&new&MessageException(name&+&"&have&no&limits.");
Map&ret&=&serviceCall.call(JMockService.queryDtlInfo,&null);
orderId&=&(String)&ret.get("OrderId");
dataList&=&(List)&ret.get("Data");
return&SUCCESS;
参数化测试
为了保证单元测试的严谨性,我们经常要模拟很多种输入参数,来确定我们的功能代码是可以正常工作的,为此我们编写大量的单元测试方法。可是这些测试方法都是大同小异:代码结构都是相同的,不同的仅仅是测试数据和期望输出值。
的参数化测试方法给我们提供了更好的方法,将测试方法中相同的代码结构提取出来,提高代码的重用度,减少复制粘贴代码的痛苦。
例如下面的功能代码(格式化字符串,将驼峰规则的字符串以"_"分隔):
public&class&WordDealUtil&{
public&static&String&wordFormat4DB(String&name)&{
if&(name&==&null)&{
return&null;
Pattern&p&=&<pile("[A-Z]");
Matcher&m&=&p.matcher(name);
StringBuffer&sb&=&new&StringBuffer();
while&(m.find())&{
if&(m.start()&!=&<span STYLE="color: #)&{
m.appendReplacement(sb,&("_"&+&m.group()).toLowerCase());
return&m.appendTail(sb).toString().toLowerCase();
没有使用参数化的测试用例代码:&
public&class&WordDealUtilTest&{
public&void&wordFormat4DBNull()&{
String&target&=&null;
String&result&=&WordDealUtil.wordFormat4DB(target);
assertNull(result);
public&void&wordFormat4DBEmpty()&{
String&target&=&"";
String&result&=&WordDealUtil.wordFormat4DB(target);
assertEquals("",&result);
public&void&wordFormat4DBegin()&{
String&target&=&"EmployeeInfo";
String&result&=&WordDealUtil.wordFormat4DB(target);
assertEquals("employee_info",&result);
public&void&wordFormat4DBEnd()&{
String&target&=&"employeeInfoA";
String&result&=&WordDealUtil.wordFormat4DB(target);
assertEquals("employee_info_a",&result);
public&void&wordFormat4DBTogether()&{
String&target&=&"employeeAInfo";
String&result&=&WordDealUtil.wordFormat4DB(target);
assertEquals("employee_a_info",&result);
看以上测试用例代码,结构相似,只是输入值与期望输出不同而已,但我们要拷贝很多代码。
使用参数化的测试用例代码:
@SuppressWarnings("unchecked")
@RunWith(Parameterized.class)
public&class&WordDealUtilTestWithParam&{
private&String&
private&String&
@Parameters
public&static&Collection&words()&{
return&Arrays.asList(new&Object[][]&{
{&"employee_info",&"employeeInfo"&},&&//&测试一般的处理情况
{&null,&null&},&&&&&&&&&&&&&&&&&&&&&&&&&//&测试&null&时的处理情况
{&"",&""&},&&&&&&&&&&&&&&&&&&&&&&&&&&&&&//&测试空字符串时的处理情况
{&"employee_info",&"EmployeeInfo"&},&&&&//&测试当首字母大写时的情况
{&"employee_info_a",&"employeeInfoA"&},&//&测试当尾字母为大写时的情况
{&"employee_a_info",&"employeeAInfo"&}&&//&测试多个相连字母大写时的情况
public&WordDealUtilTestWithParam(String&expected,&String&target)&{
this.expected&=&
this.target&=&
public&void&wordFormat4DB()&{
Assert.assertEquals(expected,&WordDealUtil.wordFormat4DB(target));
转自:http://www.blogjava.net/jnbzwm/archive//340801.html
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

我要回帖

更多关于 综影视随心所欲 的文章

 

随机推荐