TestNG + PowerMock 单元测试(下)

简介: 单元测试(Unit Testing),是指对软件或项目中最小可测试单元进行正确性检验的测试工作。单元是人为规定最小可测试的功能模块,可以是一个模块,一个函数或者一个类。单元测试需要与模块开发进行隔离情况下进行测试。

进阶使用


1. 参数化批量测试


在测试数据比较多的时候,我们可以通过 @DataProvider 生成数据源,通过 @Test(dataProvider = "xxx") 使用数据, 如下所示:


import com.test.testng.BaseTest;
import com.test.testng.dto.UserDto;
import org.mockito.InjectMocks;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertFalse;
import static org.testng.AssertJUnit.assertTrue;
public class UserServiceTest2 extends BaseTest {
    @InjectMocks
    private UserService userService;
    // 定义数据源
    @DataProvider(name = "test")
    public static Object[][] userList() {
        UserDto dto1 = new UserDto();
        UserDto dto2 = new UserDto();
        dto2.setSex(1);
        UserDto dto3 = new UserDto();
        dto3.setSex(1);
        dto3.setFlag(1);
        UserDto dto4 = new UserDto();
        dto4.setSex(1);
        dto4.setFlag(1);
        dto4.setAge(1);
        return new Object[][] {{dto1, null}, {dto2, null}, {dto3, null}, {dto4, null}};
    }
    // 正确场景
    @Test
    public void testCheckEffectiveUser() {
        UserDto dto = new UserDto();
        dto.setSex(1);
        dto.setFlag(1);
        dto.setAge(18);
        boolean result = userService.checkEffectiveUser(dto);
        assertTrue(result);
    }
    // 错误场景
    @Test(dataProvider = "test")
    public void testCheckEffectiveUser(UserDto dto, Object object) {
        boolean result = userService.checkEffectiveUser(dto);
        assertFalse(result);
    }
}


2.  复杂判断保证测试覆盖率


案例:


判断有效用户: 年龄大于 18 并且 sex = 1 并且 flag = 1


public boolean checkEffectiveUser(UserDto dto) {
    // 判断有效用户: 年龄大于 18 并且 sex = 1 并且 flag = 1
    return Objects.equals(dto.getSex(), 1) &&
        Objects.equals(dto.getFlag(), 1) &&
        dto.getAge() != null && dto.getAge() >= 18;
}


拆分逻辑。将其转换为最简单的 if ... else 语句。然后增加的单元测试,如下所示:


public boolean checkEffectiveUser(UserDto dto) {
    if (!Objects.equals(dto.getSex(), 1)) {
        return false;
    }
    if (!Objects.equals(dto.getFlag(), 1)) {
        return false;
    }
    if (dto.getAge() == null) {
        return false;
    }
    if (dto.getAge() < 18) {
        return false;
    }
    return true;
}


拆分后我们可以看到,咱们只需要 5 条单元测试就能做到全覆盖。


public class UserServiceTest extends BaseTest {
    @InjectMocks
    private UserService userService;
    // 覆盖第一个 return 
    @Test
    public void testCheckEffectiveUser_0() {
        UserDto dto =new UserDto();
        boolean result = userService.checkEffectiveUser(dto);
        assertFalse(result);
    }
    // 覆盖第二个 return 
    @Test
    public void testCheckEffectiveUser_1() {
        UserDto dto =new UserDto();
        dto.setSex(1);
        boolean result = userService.checkEffectiveUser(dto);
        assertFalse(result);
    }
    // 覆盖第三个 return 
    @Test
    public void testCheckEffectiveUser_2() {
        UserDto dto =new UserDto();
        dto.setSex(1);
        dto.setFlag(1);
        boolean result = userService.checkEffectiveUser(dto);
        assertFalse(result);
    }
    // 覆盖第四个 return
    @Test
    public void testCheckEffectiveUser_3() {
        UserDto dto =new UserDto();
        dto.setSex(1);
        dto.setFlag(1);
        dto.setAge(1);
        boolean result = userService.checkEffectiveUser(dto);
        assertFalse(result);
    }
    // 覆盖第五个 return
    @Test
    public void testCheckEffectiveUser_4() {
        UserDto dto =new UserDto();
        dto.setSex(1);
        dto.setFlag(1);
        dto.setAge(18);
        boolean result = userService.checkEffectiveUser(dto);
        assertTrue(result);
    }
}


单测覆盖率检测检测


image.png


3. 通过断言校验方法参数


assert:断言是 java 的一个保留字,用来对程序进行调试,后接逻辑运算表达式,如下:


int a = 0, b = 1;
assert a == 0 && b == 0;
// 使用方法:javac编译源文件,再java -ea class文件名即可。


在 Spring-Boot 中可以使用 Spring 提供的 Assert 类的方法对前端来的参数进行校验,如:


// 检查年龄 >= 18 岁
public boolean checkUserAge(UserDto dto){
    Assert.notNull(dto.getAge(), "用户年龄不能为空");
    Assert.isTrue(dto.getAge() >= 18, "用户年龄不能小于 18 岁");
    return Boolean.TRUE;
}


如果是需要转换为,rest api 返回的统一相应消息,我们可以通过:


@ControllerAdvice
public class GlobalExceptionHandler {
    @ResponseBody
    @ExceptionHandler(value = IllegalArgumentException.class)
    public Response<String> handleArgError(IllegalArgumentException e){
        return new Response().failure().message(e.getMessage());
    }
}


如何设计程序


在功能模块的设计过程中我们因该遵循一下原则(参考 《软件工程-结构化设计准则》):


  1. 模块大小适中


  1. 合适的系统调用深度


  1. 多扇入、少扇出(增加复用度, 减少依赖程度)


  1. 单入口,单出口


  1. 模块的作用域,应该在模块内


  1. 功能应该可以预测的


  1. 高内聚,低耦合


  1. 系统分解有层次


  1. 较少的数据冗余


参考文档





相关文章
|
2月前
|
XML Java 测试技术
TestNG 与 JUnit 测试框架:哪个更好?
【2月更文挑战第16天】
49 1
TestNG 与 JUnit 测试框架:哪个更好?
|
12月前
|
Java 测试技术 Maven
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(1)
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(1)
256 0
|
12月前
|
Java 测试技术
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(2)
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(2)
176 0
|
12月前
|
Java 测试技术
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(3)
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(3)
145 0
|
12月前
|
Java 测试技术
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(4)
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(4)
444 0
|
12月前
|
Java 测试技术
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(5)
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(5)
112 0
|
12月前
|
Java 测试技术
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(6)
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(6)
121 0
|
12月前
|
Java 测试技术
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(7)
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(7)
146 0
|
12月前
|
Java 测试技术
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(8)
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(8)
102 0
|
12月前
|
Java 测试技术
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(9)
《Java单元测试实战》——基础知识:Java单元测试技巧之PowerMock(9)
157 0