使用JUnit和Mockito进行单元测试!

举报
bug菌 发表于 2025/06/05 12:06:31 2025/06/05
【摘要】 🏆 本文精选收录于《滚雪球学SpringBoot》专栏,专为零基础学习者量身打造。从Spring基础到项目实战,手把手带你掌握核心技术,助力你快速提升,迈向职场巅峰,开启财富自由之路🚀!无论你是刚入门的小白,还是已有基础的开发者,都能在这里找到适合自己的学习路径!    🌟 关注、收藏、订阅,持续更新中!和我们一起高速成长,突破自我!💡

🏆本文收录于「滚雪球学SpringBoot」专栏(全网一个名),手把手带你零基础入门Spring Boot,从入门到就业,助你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!

环境说明:Windows 10 + IntelliJ IDEA 2021.3.2 + Jdk 1.8

前言 🤔

在现代Java开发中,单元测试是保证代码质量和稳定性的重要手段。JUnitMockito是两款非常流行的测试工具,JUnit用于编写和运行测试,而Mockito用于模拟依赖和行为。结合这两者,我们能够编写出高效且易于维护的单元测试。今天,我们将一起学习如何使用JUnit和Mockito进行单元测试,确保我们的代码在开发过程中能够保持高质量。🚀


目录 📋

  1. JUnit基础知识 📝
  2. Mockito基础知识 🧩
  3. 使用JUnit和Mockito进行单元测试 🧪
  4. 测试常见的场景与技巧 ⚙️
  5. 测试报告与调试 🔍

1. JUnit基础知识 📝

JUnit是Java中最常用的测试框架之一,用于编写和运行单元测试。JUnit的版本有很多,当前常用的是JUnit 5(Jupiter)。JUnit提供了测试用例的组织、断言(assertions)和生命周期管理等功能。

1.1 JUnit 5基本注解

  • @Test:标记一个方法为测试方法。
  • @BeforeEach:在每个测试方法执行之前执行的方法,通常用于初始化测试数据。
  • @AfterEach:在每个测试方法执行之后执行的方法,通常用于清理资源。
  • @BeforeAll:在所有测试方法执行之前执行的方法(静态方法)。
  • @AfterAll:在所有测试方法执行之后执行的方法(静态方法)。
  • @Disabled:暂时禁用某个测试方法。

1.2 JUnit的断言方法

JUnit提供了很多断言方法,帮助我们验证测试结果:

  • assertEquals(expected, actual):验证预期值与实际值是否相等。
  • assertNotNull(object):验证对象是否不为null
  • assertTrue(condition):验证条件是否为true
  • assertFalse(condition):验证条件是否为false

示例:

@Test
void testAddition() {
    int sum = 2 + 3;
    assertEquals(5, sum);  // 验证2 + 3是否等于5
}

2. Mockito基础知识 🧩

Mockito是一个用于模拟对象和方法的框架,常用于单元测试中模拟依赖对象,从而进行隔离测试。Mockito提供了简单且强大的API来模拟对象行为、验证方法调用、处理异常等。

2.1 创建Mock对象

Mockito允许我们创建一个mock对象,模拟接口或类的行为,而不需要依赖于真实的实现。

示例:

// 创建一个mock对象
List<String> mockedList = Mockito.mock(List.class);

2.2 模拟方法返回值

使用Mockito.when()来指定mock对象的方法行为。

示例:

Mockito.when(mockedList.get(0)).thenReturn("Hello");  // 模拟mockedList.get(0)返回"Hello"

2.3 验证方法调用

Mockito提供了Mockito.verify()方法来验证mock对象的方法是否被调用。

示例:

mockedList.add("Hello");
Mockito.verify(mockedList).add("Hello");  // 验证add("Hello")方法是否被调用

3. 使用JUnit和Mockito进行单元测试 🧪

3.1 配置JUnit和Mockito依赖

pom.xml中,添加JUnit和Mockito的依赖。

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.7.0</version>
    <scope>test</scope>
</dependency>

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>3.7.7</version>
    <scope>test</scope>
</dependency>

3.2 编写一个简单的测试类

假设我们有一个UserService类,依赖于UserRepository。我们想要通过Mockito模拟UserRepository,并验证UserService的行为。

UserRepository.java

public interface UserRepository {
    User findById(Long id);
    void save(User user);
}

UserService.java

public class UserService {

    private UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public User getUser(Long id) {
        return userRepository.findById(id);
    }

    public void createUser(User user) {
        userRepository.save(user);
    }
}

UserServiceTest.java

import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import static org.mockito.Mockito.*;

import static org.junit.jupiter.api.Assertions.*;

class UserServiceTest {

    @Test
    void testGetUser() {
        // 创建Mock对象
        UserRepository mockedRepository = Mockito.mock(UserRepository.class);

        // 定义mock对象的行为
        User mockUser = new User(1L, "John Doe", 30);
        when(mockedRepository.findById(1L)).thenReturn(mockUser);

        // 创建UserService并注入mockedRepository
        UserService userService = new UserService(mockedRepository);

        // 调用方法并断言结果
        User user = userService.getUser(1L);
        assertEquals("John Doe", user.getName());
        assertEquals(30, user.getAge());
    }

    @Test
    void testCreateUser() {
        // 创建Mock对象
        UserRepository mockedRepository = Mockito.mock(UserRepository.class);

        // 创建UserService并注入mockedRepository
        UserService userService = new UserService(mockedRepository);

        // 创建一个新的用户
        User user = new User(2L, "Jane Smith", 25);

        // 调用createUser方法
        userService.createUser(user);

        // 验证save方法是否被调用
        verify(mockedRepository).save(user);
    }
}

3.3 解释测试方法

  • testGetUser()

    • 我们创建了一个UserRepository的mock对象,模拟了findById(1L)方法返回一个用户对象。
    • 然后,我们创建了UserService对象,并注入了模拟的UserRepository
    • 最后,我们调用getUser()方法并断言返回的用户信息是否符合预期。
  • testCreateUser()

    • 我们创建了一个UserRepository的mock对象,模拟了save()方法的行为。
    • 调用createUser()方法后,我们使用verify()来验证save()方法是否被正确调用。

4. 测试常见的场景与技巧 ⚙️

4.1 模拟异常

有时候,我们需要测试方法在异常情况中的行为。Mockito可以模拟方法抛出异常。

Mockito.when(mockedRepository.findById(2L)).thenThrow(new RuntimeException("User not found"));

4.2 多次调用模拟

Mockito允许你为同一个方法模拟多次不同的返回值。

Mockito.when(mockedRepository.findById(1L))
       .thenReturn(new User(1L, "John", 30))
       .thenReturn(new User(2L, "Jane", 25));  // 第二次调用返回不同的用户

4.3 使用@Mock@InjectMocks注解

Mockito提供了@Mock@InjectMocks注解来简化mock对象和被测试类的创建。

@ExtendWith(MockitoExtension.class)  // 使用Mockito扩展
class UserServiceTest {

    @Mock
    private UserRepository userRepository;

    @InjectMocks
    private UserService userService;

    @Test
    void testGetUser() {
        User mockUser = new User(1L, "John", 30);
        when(userRepository.findById(1L)).thenReturn(mockUser);

        User user = userService.getUser(1L);
        assertEquals("John", user.getName());
    }
}

5. 测试报告与调试 🔍

5.1 使用JUnit的测试报告

JUnit提供了详细的测试执行报告,显示哪些测试通过,哪些测试失败。可以使用IDE(如IntelliJ IDEA或Eclipse)运行JUnit测试,查看测试结果。

5.2 调试测试

  • 确保你的测试代码中有充分的断言来验证方法执行的正确性。
  • 使用Mockito.verify()来验证mock对象的行为是否符合预期。
  • 使用Mockito.when()来定义mock对象的行为。

总结 🌟

通过结合使用JUnitMockito,我们可以高效地编写单元测试,确保代码的正确性和稳定性。JUnit提供了简单而强大的测试功能,而Mockito则帮助我们模拟依赖并验证方法调用。通过这两者的结合,我们能够更轻松地进行单元测试,确保代码质量。

希望今天的内容能帮助你提升测试技能,编写出更高质量的代码!🚀

🧧福利赠与你🧧

  无论你是计算机专业的学生,还是对编程有兴趣的小伙伴,都建议直接毫无顾忌的学习此专栏「滚雪球学SpringBoot」专栏(全网一个名),bug菌郑重承诺,凡是学习此专栏的同学,均能获取到所需的知识和技能,全网最快速入门SpringBoot,就像滚雪球一样,越滚越大, 无边无际,指数级提升。

  最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。

  同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板、技术文章Markdown文档等海量资料。

✨️ Who am I?

我是bug菌(全网一个名),CSDN | 掘金 | InfoQ | 51CTO | 华为云 | 阿里云 | 腾讯云 等社区博客专家,C站博客之星Top30,华为云多年度十佳博主/价值贡献奖,掘金多年度人气作者Top40,掘金等各大社区平台签约作者,51CTO年度博主Top12,掘金/InfoQ/51CTO等社区优质创作者;全网粉丝合计 30w+;更多精彩福利点击这里;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试真题、4000G PDF电子书籍、简历模板等海量资料,你想要的我都有,关键是你不来拿。

-End-

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。