目录
一、Junit
依赖:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
</dependency>
</dependencies>
注解:
注解 | 作用 |
---|---|
@Test | 用于修饰需要执行的测试方法,一般用来对某些对象进行初始化, 或者加载驱动等操作 |
@Before | 修饰的方法会在任意测试方法之前被自动执行,一般写的是正常的业务逻辑 |
@After | 修饰的方法会在任意测试方法执行之后自动被执行,一般是用来释放或关闭资源的 |
示例:
// 实际方法类
public class Cal {
public int add(int a,int b) {
return a + b;
}
public int sub(int a,int b){
return a - b;
}
}
// 测试类
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class CalTest {
@Before
public void init(){
System.out.println("init...");
}
@After
public void close(){
System.out.println("close...");
}
@Test
public void testAdd(){
Cal c = new Cal();
int result = c.add(1,2);
Assert.assertEquals(3,result);
System.out.println("testAdd...");
}
@Test
public void testSub(){
Cal c = new Cal();
int result = c.sub(1,2);
Assert.assertEquals(2,result);
System.out.println("testSub...");
}
}
testAdd 的结果:
testSub 的结果:
参考:
二 、Mockito
1.什么是 mock 测试
Mock 测试可以理解为模拟测试,就是在测试中模拟真实对象(模拟入参、指定返回结果等),从而达到不依赖实际环境完成测试(如用户入参、查数据库等)。
依赖:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>4.3.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.8.2</version>
<scope>test</scope>
</dependency>
2.Mockito 中常用的方法
mock 方法 :mock 一个类
// 示例
Random random = Mockito.mock(Random.class);
verify 方法:对 mock 出来的对象进行行为验证
// 示例:验证方法是否被调用
@Test
public void justTest(){
Random random = Mockito.mock(Random.class);
System.out.println(random.nextInt());
Mockito.verify(random).nextInt();
}
Verify 配合 time() 方法,可以校验某些操作发生的次数。
@Test
public void justTest(){
Random random = Mockito.mock(Random.class);
System.out.println(random.nextInt());
Mockito.verify(random,Mockito.times(2)).nextInt();
}
更多用法讲解:Mockito Verify的使用_BlueZhang521的博客-CSDN博客_mockito.verify
断言 Assertions 类
// 示例:
Random random = Mockito.mock(Random.class);
Assertions.assertEquals(100, random.nextInt());
输出结果:
org.opentest4j.AssertionFailedError: expected: <100> but was: <0>
Expected :100
Actual :0
当使用 mock 对象方法时,如果不对其行为进行定义(指定结果),则返回值为返回类型的默认值。
打桩
打桩可以理解为:为 mock 对象指定行为结果。
方法 | 含义 |
---|---|
when().thenReturn() | Mock 对象在触发指定行为后返回指定值 |
when().thenThrow() | Mock 对象在触发指定行为后抛出指定异常 |
when().doCallRealMethod() | Mock 对象在触发指定行为后调用真实的方法 |
when().thenReturn() 示例:
@Test
void check() {
Random random = Mockito.mock(Random.class);
Mockito.when(random.nextInt()).thenReturn(100);
Assertions.assertEquals(100, random.nextInt());
}
和上面没有进行打桩对比,此处使用 thenReturn() 方法定义了返回结果,所以使用断言判断结果正确,测试通过。
3.Mockito 中常用的注解
@Mock
@Mock
private Random random;
@Test
void check() {
MockitoAnnotations.openMocks(this);
Mockito.when(random.nextInt()).thenReturn(100);
Assertions.assertEquals(100, random.nextInt());
}
使用 @Mock 注解代替了 Mockito.Mock() 方法,等效于下面的代码。
@Test
void check() {
Random random = Mockito.mock(Random.class);
Mockito.when(random.nextInt()).thenReturn(100);
Assertions.assertEquals(100, random.nextInt());
}
注意:@Mock 注解需要搭配 MockitoAnnotations.openMocks(testClass) 方法一起使用。
@BeforeEach 与 @BeforeAfter
在 Junit5 中,@Before 和 @After 注解被 @BeforeEach 和 @AfterEach 所替代
Mockito.spy() 方法和 @Spy 注解
示例:
// Mockito.spy()方法
@Test
void check() {
UtilTest utilTest = Mockito.spy(new UtilTest());
int res = utilTest.add(1, 2);
Assertions.assertEquals(3, res);
}
// @Spy 注解
@Spy
private UtilTest utilTest;
@Test
void check() {
MockitoAnnotations.openMocks(this);
int res = utilTest.add(1, 2);
Assertions.assertEquals(3, res);
}
spy() 方法与 mock() 方法的区别:
① spy() 方法的参数是对象实例,mock 的参数是 class;
② 被 spy 的对象会走真实的方法,而 mock 对象不会(即 spy 对象会走实际 add() 方法,1+2=3;而 mock 对象不会,1+2 返回默认值 0)
三、举例
主要是为了理解各种方法怎么用,如注解、静态方法、打桩等,忽略细节。
// 服务类
public class RegistrationServiceImpl implements RegistrationService {
SalesDao salesDao = new SalesDao();
UserDao userDao = new UserDao();
@Override
public User register(String name, String phone) throws Exception {
// 参数校验
if (name == null || name.length() == 0) {
throw new ValidationException("number 不能为空");
}
if (phone == null || !isValid(phone)) {
throw new ValidationException("phone 格式错误");
}
// 通过手机号获取区域编号
String areaCode = FindUtils.getAreaCode(phone);
// 通过手机号获取运营商编号
String operatorCode = FindUtils.getOperatorCode(phone);
User user;
try {
// 通过 区域编号、运营商编号 找人
SalesRep rep = salesDao.findRep(areaCode, operatorCode);
// 将找到的人存储
user = userDao.save(name, phone, rep.getRepId());
} catch (SQLException e) {
throw new DAOException("SQLException thrown " + e.getMessage());
}
return user;
}
private boolean isValid(String phone) {
String pattern = "^(13[0-9]|14[5|7]|15[0|1|2|3|4|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\\d{8}$";
boolean flag = phone.matches(pattern);
return flag;
}
}
// 测试类
class RegistrationServiceImplTest {
@InjectMocks
@Spy
private RegistrationServiceImpl registrationService;
@Mock
private UserDao userDao;
@Mock
private SalesDao salesDao;
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}
@Test
void register() throws Exception {
String name = null;
String phone = "15071271412";
try {
registrationService.register(name, phone);
Assertions.fail("这里会挂掉");
} catch (Exception e) {
Assertions.assertTrue(e instanceof ValidationException);
}
name = "一直游到海水变蓝";
phone = null;
try {
registrationService.register(name, phone);
Assertions.fail("这里会挂掉");
} catch (Exception e) {
Assertions.assertTrue(e instanceof ValidationException);
}
phone = "15071271412";
// 静态方法 mockStatic
MockedStatic<FindUtils> staticService = Mockito.mockStatic(FindUtils.class);
staticService.when(() -> FindUtils.getAreaCode("15071271412")).thenReturn("a");
staticService.when(() -> FindUtils.getOperatorCode("15071271412")).thenReturn("b");
// 1.数据库操作正常(不执行 catch 部分代码)
Mockito.when(salesDao.findRep("a","b")).thenCallRealMethod();
Mockito.when(userDao.save(name, phone, "Echo")).thenCallRealMethod();
User user = registrationService.register(name, phone);
Assertions.assertEquals("Echo", user.getRepId());
// 2.数据库操作异常(执行 catch 部分代码)
Mockito.when(userDao.save(name, phone, "Echo")).thenThrow(new SQLException());
try {
registrationService.register(name, phone);
} catch (Exception e) {
Assertions.assertTrue(e instanceof DAOException);
}
}
}
完整代码可以找下面参考链接。
参考: