【单元测试】一文读懂java单元测试

这篇具有很好参考价值的文章主要介绍了【单元测试】一文读懂java单元测试。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1. 什么是单元测试

单元测试是软件开发中常用的一种测试方法,用于验证代码的单个功能单元是否按照预期工作。
测试方法:

  • 白盒测试(White Box Testing):在白盒测试中,测试人员了解代码的内部结构和实现细节,编写测试用例来覆盖不同的代码路径和逻辑条件。
  • 黑盒测试(Black Box Testing):黑盒测试不考虑代码的内部实现,而是基于需求规格说明或功能规范编写测试用例,测试程序的输入和输出是否符合预期。
  • 单元测试框架:使用单元测试框架可以简化单元测试的编写和执行。常见的单元测试框架包括JUnit(Java)、NUnit(.NET)、pytest(Python)等。
  • 断言(Assertion):在单元测试中,断言用于检查预期结果和实际结果是否匹配。测试人员可以使用断言来验证程序的特定行为和结果。
  • 边界值测试(Boundary Value Testing):边界值测试通过选择测试用例中的边界条件,例如最小值、最大值、临界值等,来验证程序在边界情况下的行为。
  • 异常处理测试(Exception Handling Testing):异常处理测试用于验证程序在遇到异常情况时是否能够正确地捕获和处理异常,并保证系统的稳定性和可靠性。
  • 参数化测试(Parameterized Testing):参数化测试允许在单个测试用例中使用不同的参数进行多次测试,以增加测试覆盖率和复用性。
    这些方法都可以根据具体的需求和开发环境选择使用。单元测试的目标是尽可能地覆盖代码,确保每个单元都能按照预期工作,并提高软件的质量和可维护性。

这些方法都可以根据具体的需求和开发环境选择使用。单元测试的目标是尽可能地覆盖代码,确保每个单元都能按照预期工作,并提高软件的质量和可维护性。

2. 为什么要单元测试

(1)单元测试意义:

程序代码都是由基本单元不断组合成复杂的系统,底层基本单元都无法保证输入输出正确性,层级递增时,问题就会不断放大,直到整个系统崩溃无法使用。所以单元测试的意义就在于保证基本功能是正常可用且稳定的。而对于接口、数据源等原因造成的不稳定因素,是外在原因,不在单元测试考虑范围之内。

(2)使用 main 方法进行测试:

@PostMapping("/add")
public void addStudent(@RequestBody Student student){
    studentService.save(student);
}

假如要对上面的 Controller 进行测试,可以编写如下的代码示例,使用 main 方法进行测试的时候,先启动整个工程应用,然后编写 main 方法如下进行访问,在单步调试代码。

public static void main(String[] args) {
    RestTemplate restTemplate = new RestTemplate();
    HttpHeaders httpHeaders = new HttpHeaders();
    httpHeaders.setContentType(MediaType.APPLICATION_JSON);
    String json = "{\"id\":4,\"name\":\"阿狸\",\"classname\":\"初三一班\",\"age\":16,\"sex\":\"女\"}";
    HttpEntity<String> httpEntity = new HttpEntity<>(json, httpHeaders);
    String url = "http://localhost:8080/student/add";
    ResponseEntity<Map> responseEntity = restTemplate.postForEntity(url, httpEntity, Map.class);
    System.out.println(responseEntity.getBody());
}

(3)使用 main 方法进行测试的缺点:

  1. 通过编写大量的 main 方法针对每个内容做打印输出到控制台枯燥繁琐,不具备优雅性。

  2. 测试方法不能一起运行,结果需要程序员自己判断正确性。

  3. 统一且重复性工作应该交给工具去完成。

3. 单元测试框架 - JUnit

3.1 JUnit 简介

Unit 官网:https://junit.org/。JUnit 是一个用于编写可重复测试的简单框架。它是用于单元测试框架的 xUnit 体系结构的一个实例。

JUnit 的特点:

(1) 针对于 Java 语言特定设计的单元测试框架,使用非常广泛。

(2) 特定领域的标准测试框架。

(3) 能够在多种 IDE 开发平台使用,包含 Idea、Eclipse 中进行集成。

(4) 能够方便由 Maven 引入使用。

(5) 可以方便的编写单元测试代码,查看测试结果等。

JUnit 的重要概念:

名称 功能作用
Assert 断言方法集合
TestCase 表示一个测试案例
TestSuite 包含一组 TestCase,构成一组测试
TestResult 收集测试结果

JUnit 的一些注意事项及规范:

(1) 测试方法必须使用 @Test 修饰

(2) 测试方法必须使用 public void 进行修饰,不能带参数

(3) 测试代码的包应该和被测试代码包结构保持一致

(4) 测试单元中的每个方法必须可以独立测试,方法间不能有任何依赖

(5) 测试类一般使用 Test 作为类名的后缀

(6) 测试方法使一般用 test 作为方法名的前缀

JUnit 失败结果说明:

(1) Failure:测试结果和预期结果不一致导致,表示测试不通过

(2) error:由异常代码引起,它可以产生于测试代码本身的错误,也可以是被测代码的 Bug

3.2 JUnit 内容

(1) 断言的 API

断言方法 断言描述
assertNull(String message, Object object) 检查对象是否为空,不为空报错
assertNotNull(String message, Object object) 检查对象是否不为空,为空报错
assertEquals(String message, Object expected, Object actual) 检查对象值是否相等,不相等报错
assertTrue(String message, boolean condition) 检查条件是否为真,不为真报错
assertFalse(String message, boolean condition) 检查条件是否为假,为真报错
assertSame(String message, Object expected, Object actual) 检查对象引用是否相等,不相等报错
assertNotSame(String message, Object unexpected, Object actual) 检查对象引用是否不等,相等报错
assertArrayEquals(String message, Object[] expecteds, Object[] actuals) 检查数组值是否相等,遍历比较,不相等报错
assertArrayEquals(String message, Object[] expecteds, Object[] actuals) 检查数组值是否相等,遍历比较,不相等报错
assertThat(String reason, T actual, Matcher<? super T> matcher) 检查对象是否满足给定规则,不满足报错

(2) JUnit 常用注解:

1) @Test: 定义一个测试方法 @Test (excepted=xx.class): xx.class 表示异常类,表示测试的方法抛出此异常时,认为是正常的测试通过的 @Test (timeout = 毫秒数) : 测试方法执行时间是否符合预期。

2) @BeforeClass在所有的方法执行前被执行,static 方法全局只会执行一次,而且第一个运行

3) @AfterClass在所有的方法执行之后进行执行,static 方法全局只会执行一次,最后一个运行

4) @Before在每一个测试方法被运行前执行一次

5) @After在每一个测试方法运行后被执行一次

6) @Ignore:所修饰的测试方法会被测试运行器忽略。

7) @RunWith:可以更改测试执行器使用 junit 测试执行器。

3.3 JUnit 使用

3.3.1 Controller 层单元测试

(1) Springboot 中使用 maven 引入 Junit 非常简单,使用如下依赖即可引入:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.1</version>
    <scope>test</scope>
</dependency>

(2) 上面使用 main 方法案例可以使用如下的 Junit 代码完成:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = UnittestDemoApplication.class)
class StudentControllerTest {

    @Autowired
    private WebApplicationContext webApplicationContext;

    private MockMvc mockMvc;

    @BeforeEach
    void setUp() {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }

    @Test
    void testAddStudent() throws Exception {
        // 创建一个Student对象作为请求的JSON体
        Student student = new Student();
        student.setId(6);
        student.setName("小乔");
        student.setClassname("初二三班");
        student.setAge(14);
        student.setSex("女");

        // 将Student对象转换为JSON字符串
        ObjectMapper objectMapper = new ObjectMapper();
        String json = objectMapper.writeValueAsString(student);

        // 发送POST请求
        mockMvc.perform(MockMvcRequestBuilders.post("/student/add")
                        .contentType(MediaType.APPLICATION_JSON_UTF8)
                        .accept(MediaType.APPLICATION_JSON_UTF8)
                        .content(json)
                )
                // 断言返回的状态码为200
                .andExpect(MockMvcResultMatchers.status().isOk())
                // 断言返回的JSON中包含指定的code和message
                .andExpect(MockMvcResultMatchers.jsonPath("$.code").value(200))
                .andExpect(MockMvcResultMatchers.jsonPath("$.message").value("保存成功"))
                .andDo(MockMvcResultHandlers.print());
    }
}

只需要在类或者指定方法上右键执行即可,可以直接充当 postman 工作访问指定 url,且不需要写请求代码,这些都由工具自动完成。

【单元测试】一文读懂java单元测试,Java,测试,单元测试,java,log4j,junit

(3)案例中相关组件介绍

本案例中构造 mockMVC 对象时,也可以使用如下方式:

@Autowired
private StudentController studentController;
@Before
public void setupMockMvc(){
   // 初始化MockMvc对象
   mockMvc = MockMvcBuilders.standaloneSetup(studentController).build();
}

其中 MockMVC 是 Spring 测试框架提供的用于 REST 请求的工具,是对 Http 请求的模拟,无需启动整个模块就可以对 Controller 层进行调用,速度快且不依赖网络环境。

使用 MockMVC 的基本步骤如下:

  1. mockMvc.perform 执行请求
  2. MockMvcRequestBuilders.post 或 get 构造请求
  3. MockHttpServletRequestBuilder.param 或 content 添加请求参数
  4. MockMvcRequestBuilders.contentType 添加请求类型
  5. MockMvcRequestBuilders.accept 添加响应类型
  6. ResultActions.andExpect 添加结果断言
  7. ResultActions.andDo 添加返回结果后置处理
  8. ResultActions.andReturn 执行完成后返回相应结果

3.3.2 Service 层单元测试

可以编写如下代码对 Service 层查询方法进行单测:

正例:

@RunWith(SpringRunner.class)
@SpringBootTest
public class StudentServiceTest {
 
	@Autowired
    private StudentService studentService;
 
    @Test
    public void getOne(){
        Student stu = studentService.getById(1);
        Assert.assertThat(stu.getName(), CoreMatchers.is("张三"));
    }
}

执行结果:

【单元测试】一文读懂java单元测试,Java,测试,单元测试,java,log4j,junit

反例:

@RunWith(SpringRunner.class)
@SpringBootTest
public class StudentServiceTest {
 
	@Autowired
    private StudentService studentService;
 
    @Test
    public void getOne(){
        Student stu = studentService.getById(1);
        Assert.assertThat(stu.getName(), CoreMatchers.is("李四"));
    }
}

执行结果:

【单元测试】一文读懂java单元测试,Java,测试,单元测试,java,log4j,junit

3.3.3 Dao 层单元测试

可以编写如下代码对 Dao 层保存方法进行单测:

@RunWith(SpringRunner.class)
@SpringBootTest
public class StudentDaoTest {
 
	@Autowired
    private StudentMapper studentMapper;
 
    @Test
    @Rollback(value = true)
    @Transactional
    public void insertOne() throws Exception {
   	    Student student = new Student();
        student.setId(7);
        student.setName("王五");
        student.setClassname("大一");
        student.setAge(20);
        student.setSex("男");
        int count = studentMapper.insert(student);
        Assert.assertEquals(1, count);
    }
}

【单元测试】一文读懂java单元测试,Java,测试,单元测试,java,log4j,junit
其中 @Rollback (value = true) 可以执行单元测试之后回滚所新增的数据,保持数据库不产生脏数据。

3.3.4 异常测试

(1) 在 service 层定义一个异常情况:

public void computeScore() {
   int a = 10, b = 0;
   int c = a/b;
}

(2) 在 service 的测试类中定义单元测试方法:

反例

    @Test
    public void computeScoreTest() {
        studentService.computeScore();
    }

结果:

【单元测试】一文读懂java单元测试,Java,测试,单元测试,java,log4j,junit

正例:

junit 5.0版本之前,在@Test上添加expected = ArithmeticException.class

@Test(expected = ArithmeticException.class)
    public void computeScoreTest() {
        studentService.computeScore();
    }

junit 5.0版本之后,使用Assert.assertThrows

@Test
public void computeScoreTest() {
    Assert.assertThrows(ArithmeticException.class, () -> {
        studentService.computeScore(); // This line should throw ArithmeticException
    });
}

(3) 执行单元测试也会通过,原因是 @Test 注解中的定义了异常

【单元测试】一文读懂java单元测试,Java,测试,单元测试,java,log4j,junit

3.3.5 测试套件测多个类

(1) 新建一个空的单元测试类

(2) 利用注解 @RunWith (Suite.class) @SuiteClasses 标明要一起单元测试的类

【单元测试】一文读懂java单元测试,Java,测试,单元测试,java,log4j,junit

运行结果:

【单元测试】一文读懂java单元测试,Java,测试,单元测试,java,log4j,junit

3.3.6 idea 中查看单元测试覆盖率

(1) 单测覆盖率

测试覆盖率是衡量测试过程工作本身的有效性,提升测试效率和减少程序 bug,提升产品可靠性与稳定性的指标。

统计单元测试覆盖率的意义:

1) 可以洞察整个代码中的基础组件功能的所有盲点,发现相关问题。

2) 提高代码质量,通常覆盖率低表示代码质量也不会太高,因为单测不通过本来就映射出考虑到各种情况不够充分。

3) 从覆盖率的达标上可以提高代码的设计能力。

(2) 在 idea 中查看单元测试覆盖率很简单,只需按照图中示例的图标运行,或者在单元测试方法或类上右键 Run ‘xxx’ with Coverage 即可。执行结果是一个表格,列出了类、方法、行数、分支覆盖情况。

【单元测试】一文读懂java单元测试,Java,测试,单元测试,java,log4j,junit

(3) 在代码中会标识出覆盖情况,绿色的是已覆盖的,红色的是未覆盖的。

【单元测试】一文读懂java单元测试,Java,测试,单元测试,java,log4j,junit
(4) 如果想要导出单元测试的覆盖率结果,可以使用如下图所示的方式,勾选 Open generated HTML in browser

【单元测试】一文读懂java单元测试,Java,测试,单元测试,java,log4j,junit
导出结果:

【单元测试】一文读懂java单元测试,Java,测试,单元测试,java,log4j,junit

3.3.7 JUnit 插件自动生成单测代码

(1) 安装插件

【单元测试】一文读懂java单元测试,Java,测试,单元测试,java,log4j,junit
(2)选择要生成单元测试的类,按Alt+Insert出现如下界面,选择TestMe自动生成文件

【单元测试】一文读懂java单元测试,Java,测试,单元测试,java,log4j,junit
(3)选择需要的生成模板,可以根据自己实际引入的依赖选择,此处选择Junit4+Mockito
【单元测试】一文读懂java单元测试,Java,测试,单元测试,java,log4j,junit
(4)生成的代码如下,可以生成一些基本的方法和注解,然后根据实际情况修改,可以节省一部分工作量。
【单元测试】一文读懂java单元测试,Java,测试,单元测试,java,log4j,junit

3.3.8 常用注解和配置

@Mock:创建一个模拟的对象,类似于@Autowired,但不是真实的对象,是Mock对象,这个注解使用在类属性上

@InjectMocks:创建一个实例,其余用@Mock注解创建的mock将被注入到用该实例中,这个注解使用在类属性上

@RunWith:表示一个运行器,@RunWith(PowerMockRunner.class)表示指定用PowerMockRunner运行,这个注解使用在类上

@PowerMockIgnore:这个注解表示将某些类延迟到系统类加载器加载,解决一些类加载异常。(具体类加载异常实际中还未遇见,后续补充),这个注解在类和方法上使用

@PrepareForTest:这个注解告诉PowerMock为测试准备某些类,通常是那些需要字节码操作的类。这包括带有final、private、static或native方法的类,new一个对象时,需要特殊处理(见下面的whenNew),这个注解在类和方法上使用

@Test:@Test修饰的public void方法可以作为测试用例运行。Junit会构造一个新的类实例,然后调用所有加了@Test的方法,方法执行过程中的任何异常,都会被判定为测试用例执行失败。

@Before:@Before注解的方法中的代码会在@Test注解的方法中首先被执行。可以做一些公共的前置操作:加入一些申请资源的代码:申请数据库资源,申请io资源,申请网络资源,new一些公共的对象等等。

@After:@After注解的方法中的代码会在@Test注解的方法中首先被执行。可以做一些公共的后置操作,如关闭资源的操作。

注:可以查看注解上的注释,了解其大致用法。

代码地址GitHub

单元测试之Mockito见文章《【单元测试】单元测试之Mockito的使用》
【单例测试】Mockito实战见文章《【单例测试】Mockito实战》

觉得有用的话还请来个三连!!!文章来源地址https://www.toymoban.com/news/detail-854737.html

到了这里,关于【单元测试】一文读懂java单元测试的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【java安全】Log4j反序列化漏洞

    关于Apache Log4j Log4j是Apache的开源项目,可以实现对System.out等打印语句的替代,并且可以结合spring等项目,实现把日志输出到控制台或文件等。而且它还可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码,满足了大多数要求。 就是用来打印日志的 漏洞成因

    2024年02月11日
    浏览(37)
  • java web中部署log4j.xml

    标题:Java Web中部署log4j.xml 目录: 1. 介绍 2. 配置log4j.xml文件 3. 配置web.xml文件 4. 配置Spring框架 5. 配置Spring Bean 6. 总结 ## 1. 介绍 在Java Web开发中,日志记录是非常重要的一部分。log4j是一个常用的Java日志记录框架,它提供了灵活的配置和强大的日志功能。本篇博客将介绍如何

    2024年02月09日
    浏览(34)
  • logging.level的含义及设置 【java 日志 (logback、log4j)】

    日志级别 tracedebuginfowarnerrorfatal 常用的有:debug,info,warn,error 通常我们想设置日志级别,会用到 logging.level.root=info logging.level设置日志级别,后面跟生效的区域。root表示整个项目。 也可以写某个包,或者某个类。 例如:logging.level.com.ali.service=error。在com.ali.service包下所有

    2024年02月10日
    浏览(33)
  • java 使用log4j显示到界面和文件 并格式化

    jar包https://dlcdn.apache.org/logging/log4j/2.20.0/apache-log4j-2.20.0-bin.zip sources是源码包,可以看到说明。在IDEA里先加入class jar后,再双击这个class jar包或或右键选Navigate ,Add ,选对应的Sources.jar  解释一下 \\\"%d{yyyy-MM-dd HH:mm:ss} %c [%p] - %m%n\\\" 每个部分的含义: %d{yyyy-MM-dd HH:mm:ss} :表示输出日

    2024年02月12日
    浏览(25)
  • JAVA中使用log4j及slf4j进行日志输出的方法

    JAVA中输出日志比较常用的是log4j,这里讲下log4j的配置和使用方法,以及slf4j的使用方法。 一、下载log4j的架包,并导入项目中,如下: 二、创建log4j.properties配置文件 1、log4j配置文件的位置: (1)如果是java project项目,则在项目的根目录下创建log4j.properties而不是在src目录下

    2024年02月07日
    浏览(34)
  • java slf4j,Commons Logging与log4j,Logback,tinylog和异常配合使用

    1、日志是什么?         日志是每天记录我们程序情况的。日志管理的目的是为了记录日志。 2、为什么会有日志?         1、问题追溯,通过日志文件的记录可以使我们运维或者程序员快速查找问题根源。         2、状态检测,检测我们系统状况,为项目出现的问题做

    2024年02月16日
    浏览(45)
  • Maven编译java及解决程序包org.apache.logging.log4j不存在问题

    1、首先新建一个文件夹,比如hello Hello里新建pom.xml 注意上面dependencies部分用于解决程序包org.apache.logging.log4j不存在问题,即 Maven编译java及解决程序包org.apache.logging.log4j不存在问题 和文件夹srcmainjava java里新建Exploit.java和LogTest.java Exploit.java LogTest.java 2、然后使用meve compile编

    2024年02月10日
    浏览(29)
  • 【实战】一次简单的log4j漏洞测试

    更新时间:2021.12.19 参考文档:https://www.yuque.com/u8021480/crow/dg9xax 在去年 log4j 漏洞刚爆发的时候,很多平台都存在漏洞,当时也在第一时间在有授权的情况下对某论坛进行了渗透测试,结果发现存在漏洞,报告之后,漏洞也被很快修复。 本次对该渗透过程进行一个简单的记录

    2023年04月26日
    浏览(37)
  • 安全学习_开发相关_Java第三方组件Log4j&FastJSON及相关安全问题简介

    Java Naming and Directory Interface (Java 命名和目录接口 ),JNDI 提供统一的客户端 API,通过不同的服务供应接口(SPI)的实现,由管理者将 JNDI API 映射为特定的命名服务和目录服务,使得 JAVA 应用程可以通过 JNDI 实现和这些命名服务和目录服务之间的交互。 Log4J: Apache的一个开源项目

    2024年02月05日
    浏览(44)
  • Exception in thread “main“ java.lang.NoClassDefFoundError: org/apache/logging/log4j/util/ReflectionU

     报错信息 :org.apache.logging.log4j.util.ReflectionUtil Exception in thread \\\"main\\\" java.lang.NoClassDefFoundError: org/apache/logging/log4j/util/ReflectionUtil     at org.apache.logging.slf4j.Log4jLoggerFactory.getContext(Log4jLoggerFactory.java:42)     at org.apache.logging.log4j.spi.AbstractLoggerAdapter.getLogger(AbstractLoggerAdapter.java:46

    2024年02月04日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包