马士兵JUnit4入门笔记

什么是单元测试

 

写了个类,要给别人用,会不会有bug?怎么办?测试一下。

main方法测试好不好?不好!

1.         不能一起运行!

2.         大多数情况下需要人为的观察输出确定是否正确

 

为什么要进行单元测试

 

重用测试,应付将来的实现的变化。

提高士气,明确知道我的东西是没问题的。

 

JUnit4 HelloWorld

 

1.         new project

2.         建立类

3.         建立testcase

 

放弃旧的断言,使用hamcrest断言

 

1.         assertThat(import static org.junit.Assert.*;)

2.         使用hamcrest的匹配方法(import static org.hamcrest.Matchers.*;),语法更自然

3.         示例

a)        

assertThat( n, allOf( greaterThan(1), lessThan(15) ) );
assertThat( n, anyOf( greaterThan(16), lessThan(8) ) );
assertThat( n, anything() );
assertThat( str, is( "bjsxt" ) );
assertThat( str, not( "bjxxt" ) );

b)       

assertThat( str, containsString( "bjsxt" ) );
assertThat( str, endsWith("bjsxt" ) );
assertThat( str, startsWith( "bjsxt" ) );
assertThat( n, equalTo( nExpected ) );
assertThat( str, equalToIgnoringCase( "bjsxt" ) );
assertThat( str, equalToIgnoringWhiteSpace( "bjsxt" ) );

c)        

assertThat( d, closeTo( 3.0, 0.3 ) );//3+-0.3
assertThat( d, greaterThan(3.0) );
assertThat( d, lessThan (10.0) );
assertThat( d, greaterThanOrEqualTo (5.0) );
assertThat( d, lessThanOrEqualTo (16.0) );

d)       

assertThat( map, hasEntry( "bjsxt", "bjsxt" ) );
assertThat( iterable, hasItem ( "bjsxt" ) );
assertThat( map, hasKey ( "bjsxt" ) );
assertThat( map, hasValue ( "bjsxt" ) );

 

FailureError

 

1.         Failure是指测试失败,测试没有通过要求

2.         Error是指测试程序代码本身出错

 

JUnit4 Annotation

 

1.         @Test: 测试方法

a)         (expected=XXException.class)

b)        (timeout=xxx),xxx的单位为毫秒

2.         @Ignore: 被忽略的测试方法,当某一次测试中不需要或者不能测试某个方法,加这个注解让它在本次测试中不运行,也可以放在测试类上,表示这个测试类中的所有测试方法都不运行。

3.         @Before: 同一个测试类中每一个测试方法之前运行

4.         @After: 同一个测试类中每一个测试方法之后运行

5.         @BeforeClass: 同一个测试类中所有测试开始之前运行,方法必须是static

6.         @AfterClass: 同一个测试类中所有测试结束之后运行,方法必须是static

 

运行多个测试

右键测试类所在的包->Run As->Run Configurations->在"Run all tests in the selected project, package or source folder:"中选要测试的项目的名称,然后点Run

 

注意

1.         遵守约定,比如:

a)         类放在test包中

b)        类名用XXXTest结尾,如UserTest

c)         方法用testMethod命名,如testAdd

 

其他框架

 

TestNG

 

JUnit4与JUnit3.8相比,多的一个功能就是参数化测试,即为某个测试方法提供几组测试数据来进行测试。例:

//目标类

package com.paul.junit4;

public class Calculator {
 
 public int add(int x, int y) {
  return x + y;
 }
}

 

//测试类

package com.paul.junit4;

import java.util.Arrays;
import java.util.Collection;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.*;

@RunWith(Parameterized.class) //表示不使用默认的测试运行器,而是使用参数化运行器(Parameterized.class)。类中的写法是固定的,需要一个提供数据的静态方法,用@Parameters注解,还要提供构造方法,这是由JUnit在运行时自动调用的,从而将测试数据赋给成员变量来执行测试。
public class CalculatorParametersTest {

 private int expected;
 private int linput;
 private int rinput;
 private Calculator cal;
 
 public CalculatorParametersTest(int expected, int linput, int rinput) {
  this.expected = expected;
  this.linput = linput;
  this.rinput = rinput;
 }
 
 @SuppressWarnings("unchecked")
 @Parameters
 public static Collection prepareData() {
  Object[][] array = {{8, 3, 5}, {4, 1, 3}, {4, -4, 8}, {0, -4, 4}};
  return Arrays.asList(array);
 }
 
 @Before
 public void setUp() throws Exception {
  cal = new Calculator();
 }

 @After
 public void tearDown() throws Exception {
 }

 @Test
 public void testAdd() {
  assertThat(this.expected, is(cal.add(this.linput, this.rinput)));
 }
}

 

 JUnit4没有测试套件的概念,而用的是测试套件运行器(Suite.class),例:

@RunWith(Suite.class)

@Suite.SuiteClasses({CalculatorTest.class, LargestTest.class, ParametersTest.class})

public class TestAll  {

 

}

 

@Suite.SuiteClasses中还可以继续指定Suite类,这样可以将多个Suite组合起来,JUnit会一直查找Suite中的所有的测试类,如:

@RunWith(Suite.class)

@Suite.SuiteClasses(TestAll.class)

public class TestAll2  {

 

}

 

 

测试类TestAll只是一个空的类,主要是用SuiteClasses注解来表示要一起运行的测试类有哪些。

 

 

 

 

以下是JUnit3.8的一些知识总结:

1、用命令行方式启动运行JUnit的方式:

public static void main(String[] args) {
  junit.textui.TestRunner.run(TTest.class);

 //junit.awtui.TestRunner.run(TTest.class); 此方法可能只适用于JUnit3.8
 }

在测试类TTest中写一个main方法,运行run方法,run方法中的类必须继承了TestCase,

所以我觉得这种方法只适用于JUnit3.8。

 

2、JUnit3.8中有TestSuite的概念,即将多个继承了TestCase的测试类加入到TestSuite中,

达到统一执行被加入的测试类的目的。例:

public class TestAll extends TestCase {

 public static Test suite() {
  TestSuite suite = new TestSuite();
  suite.addTestSuite(TTest.class);
  suite.addTestSuite(UserTest.class);
  return suite;
 }
}

其中,TTest和UserTest都是继承了TestCase的测试类。

TestAll本身也是一个测试类。只是用来统一执行已经写好了的别的测试类。

 

3、假如有一个目标类中有一个private访问类型的方法需要单元测试,但我们又不能修改其访问类型为public,

这时只能用反射来获取该方法并调用。例:

目标类:

package com.paul.junit4;

public class Calculator {
 
 private int add(int x, int y) {
  return x + y;
 }
}

 

测试类:

package com.paul.junit4;

import java.lang.reflect.Method;
import org.junit.Assert;
import org.junit.Test;


public class CalculatorTest {
 
 @Test
 public void testAdd() {
  Class<Calculator> clazz = Calculator.class;
  Calculator cal = new Calculator();
  Method m = null;
  try {
   m = clazz.getDeclaredMethod("add", new Class[]{Integer.TYPE, Integer.TYPE});
  } catch (Exception e) {
   e.printStackTrace();
  }
  m.setAccessible(true);
  Object result = "";
  try {
   result = m.invoke(cal, new Object[]{2, 3});
  } catch (Exception e) {
   e.printStackTrace();
  }
  Assert.assertEquals(5, result);
  /*System.out.println(Integer.class == Integer.TYPE);
  System.out.println(Integer.class);
  System.out.println(Integer.TYPE);
  System.out.println(int.class);*/
 }
}

 

 或用JUnit4的写法:

 

package com.paul.junit4;

import java.lang.reflect.Method;
import static org.junit.Assert.*;
import org.junit.Test;
import static org.hamcrest.Matchers.*;


public class CalculatorTest {
 
 @Test
 public void testAdd() {
  Class<Calculator> clazz = Calculator.class;
  Calculator cal = new Calculator();
  Method m = null;
  try {
   m = clazz.getDeclaredMethod("add", new Class[]{Integer.TYPE, Integer.TYPE});
  } catch (Exception e) {
   e.printStackTrace();
  }
  m.setAccessible(true);
  int result = 0;
  try {
   result = (Integer)m.invoke(cal, new Object[]{2, 3});
  } catch (Exception e) {
   e.printStackTrace();
  }
//  Assert.assertEquals(5, result);
  assertThat(result, is(5));
  /*System.out.println(Integer.class == Integer.TYPE);
  System.out.println(Integer.class);
  System.out.println(Integer.TYPE);
  System.out.println(int.class);*/
 }
}

 

4、如果想设定test case的执行次数,可以用RepeatedTest类。例:

package com.paul.junit4;

import static org.junit.Assert.*;
import static org.hamcrest.Matchers.*;
import junit.framework.TestCase;
import com.paul.junit4.User;

public class UserTest extends TestCase {

 //测试类必须加这个构造方法,以便传入测试方法
 public UserTest(String name) {
  super(name);
 }
 
 public void testGetName() {
  assertThat(new User().getName(), equalTo("宋慧乔"));
 }

}

 

package com.paul.junit4;

import junit.extensions.RepeatedTest;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;


public class TestAll extends TestCase {

 public static Test suite() {
  TestSuite suite = new TestSuite();
  suite.addTestSuite(TTest.class);
  suite.addTestSuite(UserTest.class);


  //20为重复执行的次数,UserTest测试类必须有一个String name的构造方法来传入要调用的测试方法名称
  suite.addTest(new RepeatedTest(new UserTest("testGetName"), 20));   return suite;
 }
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值