1. 为什么使用单元测试
主要是为了方便。试想一下,如果你写了一个工具类,要查看是否符合要求,你需要运行到手机才能反馈给你结果,如果用单元测试就能大大的缩短你自我验证的时间。
2. JUnit介绍
JUnit是Java最基础测试框架,单元测试代码是放在src/test/java
下面
dependencies {
testCompile 'junit:junit:4.12'
}
Assert类中主要方法如下:
方法名 | 方法描述 |
---|---|
assertEquals | 断言传入的预期值与实际值是相等的 |
assertNotEquals | 断言传入的预期值与实际值是不相等的 |
assertArrayEquals | 断言传入的预期数组与实际数组是相等的 |
assertNull | 断言传入的对象是为空 |
assertNotNull | 断言传入的对象是不为空 |
assertTrue | 断言条件为真 |
assertFalse | 断言条件为假 |
assertSame | 断言两个对象引用同一个对象,相当于“==” |
assertNotSame | 断言两个对象引用不同的对象,相当于“!=” |
assertThat | 断言实际值是否满足指定的条件 |
注意:上面的每一个方法,都有对应的重载方法,可以在前面加一个String类型的参数,表示如果断言失败时的提示。
JUnit 中的常用注解:
注解名 | 含义 |
---|---|
@Test | 表示此方法为测试方法 |
@Before | 在每个测试方法前执行,可做初始化操作 |
@After | 在每个测试方法后执行,可做释放资源操作 |
@Ignore | 忽略的测试方法 |
@BeforeClass | 在类中所有方法前运行。此注解修饰的方法必须是static void |
@AfterClass | 在类中最后运行。此注解修饰的方法必须是static void |
@RunWith | 指定该测试类使用某个运行器 |
@Parameters | 指定测试类的测试数据集合 |
@Rule | 重新制定测试类中方法的行为 |
@FixMethodOrder | 指定测试类中方法的执行顺序 |
执行顺序:@BeforeClass –> @Before –> @Test –> @After –> @AfterClass
3. JUnit用法
eg: 测试时间转换工具类。
public class DateUtils {
/**
* 格式:2018-11-06 15:27:21
*/
public static String getYMDHMSTime(long date) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return format.format(date);
}
public static long dateToStamp(String time) throws ParseException {
SimpleDateFormat sdr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA);
Date date = sdr.parse(time);
return date.getTime();
}
}
- 使用JUnit测试
getYMDHMSTime
基础用法
public class DateUtilsTest {
private Date mDate;
private String mTime = "2018-11-06 15:01:21";
private long timeStamp=1508054402000L;
@Before
public void setUp() throws Exception {
System.out.println("测试开始");
mDate = new Date();
mDate.setTime(timeStamp);
}
@After
public void tearDown() throws Exception {
System.out.println("测试结束");
}
@Test
public void getYMDHMSTime() throws Exception {
assertEquals("测试时间",mTime,DateUtils.getYMDHMSTime(timeStamp));
}
}
运行结果如下图所示
image.png
-
参数化测试
每次测试一个方法都要去设置对应的值,不能连续用不同的值去测试一个方法。这样是不是很麻烦,这时就用到了@RunWith
与@Parameters
。
首先在测试类上添加注解@RunWith(Parameterized.class)
,再创建一个由@Parameters
注解的public static
方法,让返回一个对应的测试数据集合。最后创建构造方法,方法的参数顺序和类型与测试数据集合一一对应。
@RunWith(Parameterized.class)
public class DateUtilsTest1 {
private String mTime;
public DateUtilsTest1(String mTime) {
this.mTime = mTime;
}
@Parameterized.Parameters
public static Collection printNumbers() {
return Arrays.asList(new String[]{
"2018-11-06",
"2018-11-06 15:01:21",
"2018年11月06日 15时01分21秒"
});
}
@Test
public void getYMDHMSTime() throws Exception {
DateUtils.dateToStamp(mTime);
}
}
上图可以看到连续执行了三次测试,其中第二次测试没有抛出异常,测试失败!
-
assertThat用法
常用的匹配器整理
匹配器 | 说明 | 例子 |
---|---|---|
is | 断言参数等于后面给出的匹配表达式 | assertThat(5, is (5)); |
not | 断言参数不等于后面给出的匹配表达式 | assertThat(5, not(6)); |
equalTo | 断言参数相等 | assertThat(30, equalTo(30)); |
equalToIgnoringCase | 断言字符串相等忽略大小写 | assertThat(“Ab”, equalToIgnoringCase(“ab”)); |
containsString | 断言字符串包含某字符串 | assertThat(“abc”, containsString(“bc”)); |
startsWith | 断言字符串以某字符串开始 | assertThat(“abc”, startsWith(“a”)); |
endsWith | 断言字符串以某字符串结束 | assertThat(“abc”, endsWith(“c”)); |
nullValue | 断言参数的值为null | assertThat(null, nullValue()); |
notNullValue | 断言参数的值不为null | assertThat(“abc”, notNullValue()); |
greaterThan | 断言参数大于 | assertThat(4, greaterThan(3)); |
lessThan | 断言参数小于 | assertThat(4, lessThan(6)); |
greaterThanOrEqualTo | 断言参数大于等于 | assertThat(4, greaterThanOrEqualTo(3)); |
lessThanOrEqualTo | 断言参数小于等于 | assertThat(4, lessThanOrEqualTo(6)); |
closeTo | 断言浮点型数在某一范围内 | assertThat(4.0, closeTo(2.6, 4.3)); |
allOf | 断言符合所有条件,相当于&& | assertThat(4,allOf(greaterThan(3), lessThan(6))); |
anyOf | 断言符合某一条件,相当于或 | assertThat(4,anyOf(greaterThan(9), lessThan(6))); |
hasKey | 断言Map集合含有此键 | assertThat(map, hasKey(“key”)); |
hasValue | 断言Map集合含有此值 | assertThat(map, hasValue(value)); |
hasItem | 断言迭代对象含有此元素 | assertThat(list, hasItem(element)); |
-
@Rule用法
还记得最上面我们在@Before
与@After
注解方法中加入”测试开始”和“测试结束”的提示信息吗?假如一直需要这样的提示,需要每次在测试类中去实现它。这样比较麻烦。这时你就可以使用@Rule
来解决这个问题。
自定义@Rule
很简单,就是实现TestRule
接口,实现apply
方法:
public class MyRule implements TestRule {
@Override
public Statement apply(final Statement base, final Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
// evaluate前执行方法相当于@Before
String className = description.getClassName();
String methodName = description.getMethodName();
System.out.println(methodName + "测试开始!");
// 运行的测试方法
base.evaluate();
//evaluate后执行方法相当于@After
System.out.println(methodName + "测试结束!");
System.out.println("Class name: "+className +", method name: "+methodName);
}
};
}
}
public class RuleTest {
@Rule
public MyRule ruleTest=new MyRule ();
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}
使用自定义的MyRule效果如下图:
image.png
网友评论