简介
JUnit迅速成为Java中开发单元测试的串实上的标准框架。被称为xUnit的相关测试框架,正在逐渐成为任何语言的标准框架。ASP、C++,C#、Eiffel.Delphi、Perl、PHP、Python、REBOL.Smalltalk和VisualBasic都有了对应的xUnit框架,这里只是列举了一些而已。
用处和特点
断言
junit 断言方法示例
- assertArrayEquals
- assertEquals : 调用equals方法比较两个对象
- assertSame: 调用== 比较两个对象,相当于比较两个对象是否使用同一个内存地址
- assertTrue: 判断 true
- assertNotNull 断言A对象不为null
Test Runners
暂时看文档没有找到合适的解释
聚集测试套件
把suites放在Runwith注解中,可以组建一个包含多个测试类在内的测试套件。
兼容junit4.0和junit3.8.x
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@RunWith(Suite.class)
@Suite.SuiteClasses({
TestFeatureLogin.class,
TestFeatureLogout.class,
TestFeatureNavigate.class,
TestFeatureUpdate.class
})
public class FeatureTestSuite {
// the class remains empty,
// used only as a holder for the above annotations
}
按顺序进行测试
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class TestMethodOrder {
@Test
public void testA() {
System.out.println("first");
}
@Test
public void testB() {
System.out.println("second");
}
@Test
public void testC() {
System.out.println("third");
}
}
测试异常
@Test(expected = IndexOutOfBoundsException.class)
public void empty() {
new ArrayList<Object>().get(0);
}
正则匹配和断言结合
assertThat(x, is(3));
assertThat(x, is(not(4)));
assertThat(responseString, either(containsString("color")).or(containsString("colour")));
assertThat(myList, hasItem("3"));
assertThat([value], [matcher statement]);
忽略类中已经测试过的类
@Ignore("Test is ignored as a demonstration")
@Test
public void testSame() {
assertThat(1, is(1));
}
给测试加上超时时间
@Test(timeout=1000)
public void testWithTimeout() {
...
}
参数化的测试
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.Collection;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class FibonacciTest {
@Parameters
public static Collection<Object[]> data() {
return Arrays.asList(new Object[][] {
{ 0, 0 }, { 1, 1 }, { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 5 }, { 6, 8 }
});
}
private int fInput;
private int fExpected;
public FibonacciTest(int input, int expected) {
fInput= input;
fExpected= expected;
}
@Test
public void test() {
assertEquals(fExpected, Fibonacci.compute(fInput));
}
}
Fibonacci函数如下:
public class Fibonacci {
public static int compute(int n) {
int result = 0;
if (n <= 1) {
result = n;
} else {
result = compute(n - 1) + compute(n - 2);
}
return result;
}
}
提供了假设机制的断言
假设机制使用举例:
例1:
@Test
public void filenameIncludesString() {
//如果文件分隔符不是’/’(forward slash),则不执行assertThat断言测试,直接跳过该测试用例函数
assumeThat(File.separatorChar, is('/'));
//判断文件名fileName是否含有字符串"developerWorks"
assertThat( fileName, containsString( "developerWorks" ) );
}
例2:
@Test
public void filenameIncludesString() {
//bugFixed不是JUnit4.4的函数,是开发人员自己工程中定义的函数,表示判断指定的defect是否
//被修正了,如果被修正,则返回true,否则返回false。这里假设缺陷13356被修正后才进行余下单元测试
assumeTrue( bugFixed("13356") );
//判断文件名fileName是否含有字符串"developerWorks"
assertThat( fileName, containsString( "developerWorks" ) );
}
rules
- 在运行测试之前,能够得到测试名以做一些需要的处理
- 指导Swing来运行测试
- 对测试失败的case加入额外信息作为参考,尤其对于selenium有作用,如抓屏
提供了理论机制的断言
import static org.hamcrest.Matchers.*; //指定接下来要使用的Matcher匹配符
import static org.junit.Assume.*; //指定需要使用假设assume*来辅助理论Theory
import static org.junit.Assert.*; //指定需要使用断言assert*来判断测试是否通过
import org.junit.experimental.theories.DataPoint; //需要使用注释@DataPoint来指定数据集
import org.junit.experimental.theories.Theories; //接下来@RunWith要指定Theories.class
import org.junit.experimental.theories.Theory; //注释@Theory指定理论的测试函数
import org.junit.runner.RunWith; //需要使用@RunWith指定接下来运行测试的类
import org.junit.Test;
//注意:必须得使用@RunWith指定Theories.class
@RunWith(Theories.class)
public class TheoryTest {
//利用注释@DataPoint来指定一组数据集,这些数据集中的数据用来证明或反驳接下来定义的Theory理论,
//testNames1和testNames2这两个理论Theory测试函数的参数都是String,所以Junit4.4会将这5个
//@DataPoint定义的String进行两两组合,统统一一传入到testNames1和testNames2中,所以参数名year
//和name是不起任何作用的,"2007"同样有机会会传给参数name,"Works"也同样有机会传给参数year
@DataPoint public static String YEAR_2007 = "2007";
@DataPoint public static String YEAR_2008 = "2008";
@DataPoint public static String NAME1 = "developer";
@DataPoint public static String NAME2 = "Works";
@DataPoint public static String NAME3 = "developerWorks";
//注意:使用@Theory来指定测试函数,而不是@Test
@Theory
public void testNames1( String year, String name ) {
assumeThat( year, is("2007") ); //year必须是"2007",否则跳过该测试函数
System.out.println( year + "-" + name );
assertThat( year, is("2007") ); //这里的断言语句没有实际意义,这里举此例只是为了不中断测试
}
//注意:使用@Theory来指定测试函数,而不是@Test
@Theory
public void testNames2( String year, String name ) {
assumeThat(year, is("2007")); //year必须是"2007",否则跳过该测试函数
//name必须既不是"2007"也不是"2008",否则跳过该测试函数
assumeThat(name, allOf( not(is("2007")), not(is("2008"))));
System.out.println( year + "-" + name );
assertThat( year, is("2007") ); //这里的断言语句没有实际意义,这里举此例只是为了不中断测试
}
结果输出:
第一个Theory打印出:
2007-2007
2007-2008
2007-developer
2007-Works
2007-developerWorks
第二个Theory打印出:
2007-developer
2007-Works
2007-developerWorks
分组测试
public class A {
@Test
public void a() {
fail();
}
@Category(SlowTests.class)
@Test
public void b() {
System.out.println("A b()");
}
}
@Category( { SlowTests.class, FastTests.class })
public class B {
@Test
public void c() {
System.out.println("B c()");
}
}
@RunWith(Categories.class)//这个地方与一般的套件测试有所不同
@IncludeCategory(SlowTests.class)
@SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite
public class SlowTestSuite {
// Will run A.b and B.c, but not A.a
}
未介绍的功能
- Test Fixtures
- Use with Maven
- Multithreaded code and Concurrency
- Java contract test helpers
- Continuous Testing