随笔 2019年8月26日
单元测试
什么是单元测试
单元测试是对软件或程序的基本(最小)组成。
特点:
- 可重复执行
- 执行速度快
- 独立无依赖
- 结果不改变
为什么要写单元测试
- 使我们更了解需求
- 快速验证
- 使重构更容易
- 更早了解程序的问题
Junit
例子
import org.junit.*;
import static org.junit.Assert.fail;
public class ClassNameTest {
@BeforeClass //公开表态无返回值
public static void beforeClass() throws Exception{
//每次测试类执行前执行一次,主要用来初使化公共资源等
}
@AfterClass //公开表态无返回值
public static void afterClass() throws Exception{
//每次测试类执行完成后执行一次,主要用来释放资源或清理工作
}
@Before
public void setup() throws Exception {
//每个测试案例执行前都会执行一次
}
@After
public void teardown() throws Exception {
//每个测试案例执行完成后都会执行一次
}
@Test
public void testMethodName_give_…_when_…_then_…() {
fail("失败");
}
}
常用的注解
-
@Ignore
该注解标记的测试方法在测试中会被忽略。
-
@Test
@Test(expected=xxxException.class) 断言该方法会抛出异常
@Test(timeout=1000) 执行时间超过设置的值该案例会失败 -
@RunWith
@RunWith(Suite.class) 测试集运行器配合使用测试集功能
@RunWith(JUnit4.class) 默认运行器
@RunWith(Parameterized.class) 参数化运行器 -
@Before
初始化方法,在任何一个测试方法执行之前,必须执行的代码。对比 JUnit 3 ,和 setUp()方法具有相同的功能。在该注解的方法中,可以进行一些准备工作,比如初始化对象,打开网络连接等。
-
@After
释放资源,在任何一个测试方法执行之后,需要进行的收尾工作。对比 JUnit 3 ,和 tearDown()方法具有相同的功能。
-
@BeforeClass
针对所有测试,也就是整个测试类中,在所有测试方法执行前,都会先执行由它注解的方法,而且只执行一次。当然,需要注意的是,修饰符必须是 public static void xxxx ;此 Annotation 是 JUnit 4 新增的功能。
-
@AfterClass
针对所有测试,也就是整个测试类中,在所有测试方法都执行完之后,才会执行由它注解的方法,而且只执行一次。当然,需要注意的是,修饰符也必须是 public static void xxxx ;此 Annotation 也是 JUnit 4 新增的功能,与 @BeforeClass 是一对。
断言
常用的断言方法如下:
assertEquals(a, b)
测试a是否等于b(a和b是原始类型数值(primitive value)或者必须为实现比较而具有equal方法)assertFalse(a)
测试a是否为false(假),a是一个Boolean数值。assertTrue(a)
测试a是否为true(真),a是一个Boolean数值assertNotNull(a)
测试a是否非空,a是一个对象或者null。assertNull(a)
测试a是否为null,a是一个对象或者null。assertNotSame(a, b)
测试a和b是否没有都引用同一个对象。assertSame(a, b)
测试a和b是否都引用同一个对象。fail(string)
Fail让测试失败,并给出指定信息。assertThat(expected, Matcher)
通过Matcher断言
执行顺序
在 JUnit 4 中,单元测试用例的执行顺序为:
@Before → @Before → @Test → @After → @AfterClass
建议
要写注释,建议分为如下4步骤。
- 测试场景
- 准备数据
- 测试执行
- 断言
Mock
前言
为什么需要Mock或Stub?它与Junit什么关系?
在做单元测试的时候,我们会发现我们要测试的方法会引用很多外部依赖的对象。 而我们没法控制这些外部依赖的对象。为了解决这个问题,我们需要用到Stub和Mock来模拟这些外部依赖的对象,从而控制它们。
JUnit是单元测试框架,可以轻松的完成关联依赖关系少或者比较简单的类的单元测试,但是对于关联到其它比较复杂的类或对运行环境有要求的类的单元测试,模拟环境或者配置环境会非常耗时,实施单元测试比较困难。而这些Mock框架(Mockito 、jmock 、 powermock、EasyMock),可以通过mock框架模拟一个对象的行为,从而隔离开我们不关心的其他对象,使得测试变得简单。
例如: service调用dao,即service依赖dao,我们可以通过mock dao来模拟真实的dao调用,从而能达到测试service的目的。
模拟对象(Mock Object)可以取代真实对象的位置,用于测试一些与真实对象进行交互或依赖于真实对象的功能,模拟对象的背后目的就是创建一个轻量级的、可控制的对象来代替测试中需要的真实对象,模拟真实对象的行为和功能。
Mock与Stub什么区别?
Mock和Stub是两种测试代码功能的方法。Mock测重于对功能的模拟,Stub测重于对功能的测试重现。比如对于List接口,Mock会直接对List进行模拟,而Stub会新建一个实现了List的TestList,在其中编写测试的代码。
强烈建议优先选择Mock方式,因为Mock方式下,模拟代码与测试代码放在一起,易读性好,而且扩展性、灵活性都比Stub好。
其中EasyMock和Mockito对于Java接口使用接口代理的方式来模拟,对于Java类使用继承的方式来模拟(也即会创建一个新的Class类)。Mockito支持spy方式,可以对实例进行模拟。但它们都不能对静态方法和final类进行模拟,powermock通过修改字节码来支持了此功能。