56. 【Java】单元测试:JUnit 5 从入门到实践

JUnit 5单元测试入门:从环境搭建到第一个测试用例实战 单元测试作为软件质量保障的核心实践,通过隔离验证代码单元(如方法、函数)的行为是否符合预期,确保其正确性和可靠性。其原理在于模拟各种输入和边界条件,利用断言机制自动验证输出结果,从而在代码集成前发现潜在缺陷。这一技术价值在于构建快速反馈的安全网,降低修复成本,提升代码可维护性,并支撑持续集成与重构。在Java开发领域,JUnit是事实标准的单元测试框架,广泛应用于各类业务逻辑验证、API接口测试及微服务组件测试等场景。本文基于JUnit 5实战,详解如何通过Maven/Gradle构建工具快速配置测试环境, 阅读详情

摘要: 本文是Java单元测试框架JUnit 5的完整入门指南,从零开始讲解如何在Maven项目中引入JUnit 5、编写第一个单元测试、掌握核心注解和断言方法,到参数化测试、测试覆盖率分析和最佳实践。通过计算器和用户服务等实战示例,帮助开发者建立自动化测试思维,提升代码质量和可维护性,为后续学习日志框架等高级主题打下坚实基础。

关键词: JUnit 5, 单元测试, Java测试框架, Maven项目, 测试覆盖率


在上一篇,我们学习了 Maven——这个帮你管理依赖、标准化构建流程的工具。现在你的项目有了规范的目录结构、有了自动化的构建流程,代码也能被干净地编译和打包了。

但你有没有想过一个问题:你写的代码,真的正确吗?

你可能说:“我当然试过了,我运行了 main 方法,看到输出没问题。”但是,手动测试有几个致命的弱点:

  • 你只测了一个输入组合,其他边缘情况呢?
  • 当你修改了代码,你怎么知道没有破坏之前已经工作的功能?
  • 如果项目有 100 个类、500 个方法,你怎么可能每次都手动跑一遍?
  • 在一个多人协作的项目中,你怎么保证你提交的代码不会“坑”到队友?

这就是自动化单元测试的用武之地。它让你用代码来测试代码,用自动化的方式验证每一段逻辑的正确性,并且可以在每次构建时自动运行,第一时间捕获回归问题。

今天我们要学习的是 Java 世界中最主流的单元测试框架——JUnit 5。


1. 什么是单元测试?—— 对代码的“体检”

单元测试(Unit Test) 是对软件中的最小可测试单元(通常是一个方法)进行检查和验证。它的目的是:

  • 验证代码的行为是否符合预期。
  • 捕获回归错误(修改代码后,原本正常的功能被破坏)。
  • 作为文档,展示方法的正确用法和预期行为。
  • 自动化,让测试在构建过程中自动运行,无需人工干预。

打个比方:你造了一辆汽车(整个程序),单元测试就像是对每个零件(每个方法)单独进行质量检测——刹车片是否达标、轮胎气压是否合格、发动机是否正常。而不是等到整车组装完成后再上路试驾,发现刹车失灵了才知道哪里有问题。

好的单元测试应该具备哪些特点?

特点说明
自动化无需人工干预,一键运行所有测试
可重复每次运行的结果应该一致(没有随机性)
独立每个测试用例之间互不影响,可以单独运行
快速单元测试应该毫秒级完成,不能依赖外部资源(数据库、网络等)
可读测试代码应该清晰表达“期望什么行为”
全面覆盖正常路径、边界条件、异常路径

在 Java 生态中,JUnit 是最老牌、最成熟的单元测试框架。JUnit 5 是当前的最新版本(2017 年发布),相比 JUnit 4 带来了很多改进。


2. 在 Maven 项目中引入 JUnit 5

首先,在 pom.xml 中添加 JUnit 5 的依赖:

<dependencies>
    <!-- JUnit 5 核心 API -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.10.0</version>
        <scope>test</scope>
    </dependency>
    
    <!-- JUnit 5 运行时引擎(用于执行测试) -->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.10.0</version>
        <scope>test</scope>
    </dependency>
</dependencies>

如果你用 IDEA 创建 Maven 项目,它通常会默认添加 JUnit 依赖。你也可以统一使用 junit-jupiter 聚合依赖:

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

scope 设置为 test,表示这个依赖只在测试阶段使用,不会被包含在最终的生产 JAR 中。


3. 编写第一个单元测试 —— 一个简单的计算器

我们来写一个简单的 Calculator 类,然后为它编写单元测试。

// src/main/java/com/example/Calculator.java
package com.example;

public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }

    public int subtract(int a, int b) {
        return a - b;
    }

    public int multiply(int a, int b) {
        return a * b;
    }

    public int divide(int a, int b) {
        if (b == 0) {
            throw new IllegalArgumentException("除数不能为0");
        }
        return a / b;
    }
}

现在,在 src/test/java 目录下创建对应的测试类:

// src/test/java/com/example/CalculatorTest.java
package com.example;

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

class CalculatorTest {
    private final Calculator calculator = new Calculator();

    @Test
    void testAdd() {
        int result = calculator.add(3, 5);
        assertEquals(8, result, "3 + 5 应该等于 8");
    }

    @Test
    void testSubtract() {
        int result = calculator.subtract(10, 3);
        assertEquals(7, result, "10 - 3 应该等于 7");
    }

    @Test
    void testMultiply() {
        int result = calculator.multiply(4, 6);
        assertEquals(24, result, "4 * 6 应该等于 24");
    }

    @Test
    void testDivide() {
        int result = calculator.divide(10, 2);
        assertEquals(5, result, "10 / 2 应该等于 5");
    }

    @Test
    void testDivideByZero() {
        // 测试抛出异常的情况
        assertThrows(IllegalArgumentException.class, 
            () -> calculator.divide(10, 0),
            "除数为0应该抛出 IllegalArgumentException");
    }
}

运行测试:

  • 在 IDEA 中,右键点击测试类 → Run ‘CalculatorTest’,或者点击类名左侧的绿色三角形。
  • 在命令行中,执行 mvn test。

你会看到测试全部通过(绿色)。如果某个断言失败,JUnit 会清晰地告诉你哪个测试失败了、期望值是什么、实际值是什么。


4. JUnit 5 的核心注解

JUnit 5 提供了丰富的注解来控制测试的生命周期和行为。

注解说明
@Test标记一个方法为测试方法
@BeforeEach在每个测试方法执行之前运行(用于初始化)
@AfterEach在每个测试方法执行之后运行(用于清理)
@BeforeAll在所有测试方法执行之前运行一次(必须是 static)
@AfterAll在所有测试方法执行之后运行一次(必须是 static)
@DisplayName为测试类或测试方法指定一个可读的名称
@Disabled禁用某个测试方法(或整个类),跳过了不执行
@Nested在测试类中创建嵌套的测试类,用于分组
@Tag给测试打标签,用于筛选执行
@Timeout设置超时时间,超时则测试失败
@RepeatedTest重复执行同一个测试指定次数
4.1 @BeforeEach 和 @AfterEach 示例
class LifecycleTest {
    private List<String> list;

    @BeforeEach
    void setUp() {
        list = new ArrayList<>();
        System.out.println("准备测试数据...");
    }

    @AfterEach
    void tearDown() {
        list.clear();
        System.out.println("清理测试数据...");
    }

    @Test
    void testAdd() {
        list.add("A");
        assertEquals(1, list.size());
    }

    @Test
    void testAddMultiple() {
        list.add("A");
        list.add("B");
        assertEquals(2, list.size());
    }
}

每个测试方法都会独立执行 setUp() → 测试方法 → tearDown(),互不干扰。

4.2 @DisplayName —— 让测试报告更易读
@DisplayName("计算器测试")
class CalculatorTest {
    
    @Test
    @DisplayName("加法测试:验证 3 + 5 = 8")
    void testAdd() {
        // ...
    }
}

在 IDEA 和测试报告中,会显示 "加法测试:验证 3 + 5 = 8" 而不是 testAdd,更加直观。

4.3 @Disabled —— 临时跳过测试
@Disabled("这个测试还没写完,先跳过")
@Test
void testNotReadyYet() {
    // 待实现的测试
}

被 @Disabled 标记的测试不会被执行,但会显示在报告中(标记为跳过)。

4.4 @Nested —— 分组组织测试

对于复杂的测试类,可以用 @Nested 把相关的测试组织在一起:

class CalculatorTest {
    private Calculator calculator = new Calculator();

    @Nested
    @DisplayName("加法运算测试")
    class AddTests {
        @Test
        void testPositiveNumbers() {
            assertEquals(5, calculator.add(2, 3));
        }
        @Test
        void testNegativeNumbers() {
            assertEquals(-5, calculator.add(-2, -3));
        }
    }

    @Nested
    @DisplayName("除法运算测试")
    class DivideTests {
        @Test
        void testNormalDivision() {
            assertEquals(5, calculator.divide(10, 2));
        }
        @Test
        void testDivisionByZero() {
            assertThrows(IllegalArgumentException.class, 
                () -> calculator.divide(10, 0));
        }
    }
}

这样测试报告会清晰地按功能分组展示。


5. 断言 —— 验证期望结果

JUnit 5 提供了 Assertions 类,包含丰富的断言方法,用于验证实际结果是否与预期一致。

断言方法说明
assertEquals(expected, actual)验证两个值是否相等
assertNotEquals(expected, actual)验证两个值不相等
assertTrue(condition)验证条件为 true
assertFalse(condition)验证条件为 false
assertNull(obj)验证对象为 null
assertNotNull(obj)验证对象不为 null
assertSame(expected, actual)验证两个引用指向同一个对象
assertNotSame(expected, actual)验证两个引用指向不同对象
assertArrayEquals(expectedArray, actualArray)验证两个数组相等
assertIterableEquals(expected, actual)验证两个 Iterable 相等
assertThrows(exceptionClass, executable)验证代码块抛出指定异常
assertDoesNotThrow(executable)验证代码块不抛出异常
assertTimeout(timeout, executable)验证代码块在指定时间内完成
fail(message)直接失败(用于标记未完成的测试)
5.1 常见断言示例
import static org.junit.jupiter.api.Assertions.*;

class AssertionDemo {
    @Test
    void testAssertions() {
        // 基本相等
        assertEquals(10, 5 + 5);
        
        // 带失败信息的字符串
        assertEquals(10, 5 + 4, "5 + 4 应该等于 10");  // 会失败,显示错误消息
        
        // 布尔值
        assertTrue(5 > 3);
        assertFalse(3 > 5);
        
        // null
        String s = null;
        assertNull(s);
        
        // 数组
        int[] expected = {1, 2, 3};
        int[] actual = {1, 2, 3};
        assertArrayEquals(expected, actual);
        
        // 异常
        assertThrows(IllegalArgumentException.class, () -> {
            Integer.parseInt("abc");
        });
        
        // 超时验证
        assertTimeout(Duration.ofSeconds(1), () -> {
            // 如果这里执行超过1秒,测试失败
            Thread.sleep(500);
        });
    }
}
5.2 分组断言(assertAll)

当你想同时验证多个条件时,可以用 assertAll 将它们分组,这样即使第一个断言失败,后面的断言仍会执行。非常适合验证一个对象的多个属性:

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

@Test
void testPerson() {
    Person person = new Person("张三", 25);
    
    // 所有断言都会执行,收集所有失败
    assertAll("person",
        () -> assertEquals("张三", person.getName()),
        () -> assertEquals(25, person.getAge()),
        () -> assertNotNull(person.getEmail())
    );
}

6. 参数化测试 —— 用多组数据测试同一个逻辑

很多时候,我们需要用多组不同的输入来测试同一个方法。比如测试 add 方法,你可能想验证 (2,3)→5、(0,0)→0、(-1,1)→0 等多组数据。

JUnit 5 的参数化测试让你可以方便地做这件事。

首先需要添加额外的依赖:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-params</artifactId>
    <version>5.10.0</version>
    <scope>test</scope>
</dependency>

然后使用 @ParameterizedTest 和对应的数据源注解:

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.ValueSource;
import static org.junit.jupiter.api.Assertions.*;

class ParameterizedCalculatorTest {
    private final Calculator calculator = new Calculator();

    // 使用 @ValueSource 提供单个参数
    @ParameterizedTest
    @ValueSource(ints = {1, 2, 3, 4, 5})
    void testIsPositive(int number) {
        assertTrue(number > 0);
    }

    // 使用 @CsvSource 提供多参数
    @ParameterizedTest
    @CsvSource({
        "1, 2, 3",
        "0, 0, 0",
        "-1, 1, 0",
        "10, -5, 5",
        "-5, -3, -8"
    })
    void testAdd(int a, int b, int expected) {
        assertEquals(expected, calculator.add(a, b));
    }

    // 使用 @MethodSource 提供更复杂的参数生成
    @ParameterizedTest
    @MethodSource("divisionTestData")
    void testDivide(int a, int b, int expected) {
        assertEquals(expected, calculator.divide(a, b));
    }

    static Stream<Arguments> divisionTestData() {
        return Stream.of(
            Arguments.of(10, 2, 5),
            Arguments.of(9, 3, 3),
            Arguments.of(100, 10, 10)
        );
    }
}

参数化测试让你的测试代码变得极其精简,用几行代码就覆盖了多种输入场景。


7. 测试覆盖率 —— 你的测试覆盖了多少代码?

测试覆盖率(Test Coverage) 衡量的是:你的测试代码执行了生产代码中的多少百分比。

常用的覆盖指标包括:

  • 行覆盖率:测试执行了多少行代码?
  • 分支覆盖率:测试覆盖了多少个 if-else 分支?
  • 方法覆盖率:测试调用了多少方法?

高覆盖率不能保证程序没有 bug,但低覆盖率一定意味着你还有很多代码没有测试过。

在 IDEA 中,右键点击测试类 → Run ‘CalculatorTest’ with Coverage,IDEA 会运行测试并显示代码覆盖情况——绿色表示被执行到,红色表示没有执行到。

你可以在 pom.xml 中配置 jacoco-maven-plugin 来生成覆盖率报告:

<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.11</version>
    <executions>
        <execution>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
        </execution>
        <execution>
            <id>report</id>
            <phase>test</phase>
            <goals>
                <goal>report</goal>
            </goals>
        </execution>
    </executions>
</plugin>

然后执行 mvn clean test jacoco:report,在 target/site/jacoco/index.html 查看详细的覆盖率报告。


8. 单元测试的最佳实践

✅ 好的做法
  1. 测试每个 public 方法:特别是包含业务逻辑的方法。
  2. 覆盖多种场景:正常路径、边界条件(0、null、空集合)、异常路径。
  3. 测试独立性:每个测试方法之间不应该有依赖关系,执行顺序应该无关紧要。
  4. 使用有意义的命名:测试方法名应该描述“在什么条件下,期望什么行为”,比如 shouldReturnTrueWhenAgeIsGreaterThan18()。
  5. 使用 @DisplayName:让测试报告易读。
  6. 保持测试快速:单元测试不应该依赖数据库、网络、文件系统。如果需要,可以用 Mock 工具(如 Mockito)模拟外部依赖。
  7. 在每次构建时运行测试:集成到 CI/CD 流水线中,第一时间发现回归问题。
❌ 避免的做法
  1. 不要在测试中写复杂逻辑:测试应该简单、直接,不应该包含 if、for 等控制流。
  2. 不要测试私有方法:私有方法是实现细节,应该通过 public 方法间接测试。
  3. 不要在测试之间共享状态:使用 @BeforeEach 重置状态,而不是在测试之间共享变量。
  4. 不要忽略测试失败:失败的测试应该立即修复,而不是注释掉或忽略。
  5. 不要只测试快乐路径:边缘条件和异常同样重要。

9. 综合示例 —— 完整的“用户服务”测试

我们来写一个更贴近实际的小例子:一个用户服务,包含注册和登录逻辑。

// UserService.java
package com.example.demo;

import java.util.*;
import java.util.regex.Pattern;

public class UserService {
    private final Map<String, User> users = new HashMap<>();
    private static final Pattern EMAIL_PATTERN = 
        Pattern.compile("^[A-Za-z0-9+_.-]+@(.+)$");

    public User register(String email, String password, String name) {
        if (email == null || email.isBlank()) {
            throw new IllegalArgumentException("邮箱不能为空");
        }
        if (!EMAIL_PATTERN.matcher(email).matches()) {
            throw new IllegalArgumentException("邮箱格式不正确");
        }
        if (password == null || password.length() < 6) {
            throw new IllegalArgumentException("密码长度至少为6位");
        }
        if (users.containsKey(email)) {
            throw new IllegalStateException("该邮箱已被注册");
        }
        User user = new User(email, password, name);
        users.put(email, user);
        return user;
    }

    public User login(String email, String password) {
        User user = users.get(email);
        if (user == null) {
            throw new IllegalArgumentException("用户不存在");
        }
        if (!user.getPassword().equals(password)) {
            throw new IllegalArgumentException("密码错误");
        }
        return user;
    }

    public Optional<User> findByEmail(String email) {
        return Optional.ofNullable(users.get(email));
    }

    public static class User {
        private final String email;
        private final String password;
        private final String name;
        private final long createdAt;

        public User(String email, String password, String name) {
            this.email = email;
            this.password = password;
            this.name = name;
            this.createdAt = System.currentTimeMillis();
        }

        public String getEmail() { return email; }
        public String getPassword() { return password; }
        public String getName() { return name; }
        public long getCreatedAt() { return createdAt; }
    }
}

测试代码:

// UserServiceTest.java
package com.example.demo;

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

@DisplayName("用户服务测试")
class UserServiceTest {
    private UserService userService;

    @BeforeEach
    void setUp() {
        userService = new UserService();
    }

    @Nested
    @DisplayName("注册功能测试")
    class RegisterTests {
        @Test
        @DisplayName("成功注册")
        void shouldRegisterSuccessfully() {
            UserService.User user = userService.register("test@example.com", "password123", "测试用户");
            
            assertAll("注册成功",
                () -> assertNotNull(user),
                () -> assertEquals("test@example.com", user.getEmail()),
                () -> assertEquals("测试用户", user.getName()),
                () -> assertTrue(userService.findByEmail("test@example.com").isPresent())
            );
        }

        @Test
        @DisplayName("邮箱为空时抛出异常")
        void shouldThrowWhenEmailIsBlank() {
            assertThrows(IllegalArgumentException.class, 
                () -> userService.register("", "password123", "测试用户"),
                "邮箱不能为空"
            );
        }

        @Test
        @DisplayName("邮箱格式不正确时抛出异常")
        void shouldThrowWhenEmailIsInvalid() {
            assertThrows(IllegalArgumentException.class, 
                () -> userService.register("invalid-email", "password123", "测试用户"),
                "邮箱格式不正确"
            );
        }

        @Test
        @DisplayName("密码太短时抛出异常")
        void shouldThrowWhenPasswordTooShort() {
            assertThrows(IllegalArgumentException.class, 
                () -> userService.register("test@example.com", "123", "测试用户"),
                "密码长度至少为6位"
            );
        }

        @Test
        @DisplayName("重复注册时抛出异常")
        void shouldThrowWhenEmailAlreadyExists() {
            userService.register("test@example.com", "password123", "测试用户");
            
            assertThrows(IllegalStateException.class, 
                () -> userService.register("test@example.com", "newpass", "测试用户2"),
                "该邮箱已被注册"
            );
        }
    }

    @Nested
    @DisplayName("登录功能测试")
    class LoginTests {
        @Test
        @DisplayName("成功登录")
        void shouldLoginSuccessfully() {
            userService.register("test@example.com", "password123", "测试用户");
            UserService.User user = userService.login("test@example.com", "password123");
            
            assertNotNull(user);
            assertEquals("test@example.com", user.getEmail());
        }

        @Test
        @DisplayName("用户不存在时登录失败")
        void shouldThrowWhenUserNotFound() {
            assertThrows(IllegalArgumentException.class, 
                () -> userService.login("unknown@example.com", "password123"),
                "用户不存在"
            );
        }

        @Test
        @DisplayName("密码错误时登录失败")
        void shouldThrowWhenPasswordWrong() {
            userService.register("test@example.com", "password123", "测试用户");
            
            assertThrows(IllegalArgumentException.class, 
                () -> userService.login("test@example.com", "wrongpassword"),
                "密码错误"
            );
        }
    }
}

这个测试覆盖了:

  • 正常流程(成功注册、成功登录)
  • 边界条件(空邮箱、无效邮箱、密码太短)
  • 异常场景(重复注册、用户不存在、密码错误)
  • 使用 @Nested 组织测试分组
  • 使用 @DisplayName 让测试报告清晰可读
  • 使用 assertAll 验证多个条件

10. 今天的总结

今天我们学习了 JUnit 5 单元测试:

  • 什么是单元测试:用代码验证代码,确保每个方法的行为符合预期。
  • JUnit 5 核心注解:@Test、@BeforeEach、@AfterEach、@BeforeAll、@AfterAll、@DisplayName、@Disabled、@Nested。
  • 断言:assertEquals、assertTrue、assertNull、assertThrows、assertAll 等。
  • 参数化测试:用 @ParameterizedTest + @ValueSource、@CsvSource、@MethodSource 多组数据测试同一个逻辑。
  • 测试覆盖率:用 JaCoCo 生成覆盖率报告,衡量测试的充分性。
  • 最佳实践:测试独立性、覆盖多种场景、快速执行、不测试私有方法等。

单元测试是保证代码质量的“安全网”。有了它,你可以放心地重构代码、添加新功能,因为一旦破坏了任何已有功能,测试会立刻告诉你。


动手试试

  1. 为之前写的 StringUtil 工具类编写单元测试,覆盖 isBlank、isEmpty、reverse、capitalize 等方法。

  2. 在 Calculator 中添加一个 pow(int a, int b) 方法,然后用参数化测试验证多组输入(比如 (2,3)→8、(3,2)→9、(10,0)→1)。

  3. 写一个 BankAccount 类,包含 deposit、withdraw、getBalance 方法。编写测试覆盖:正常存钱、正常取钱、余额不足时取钱抛出异常、取负数金额抛出异常。

  4. 在你的 pom.xml 中添加 JaCoCo 插件,运行 mvn clean test jacoco:report,查看覆盖率报告,看看你的测试覆盖了哪些代码。

  5. 修改一个已有的测试,让它失败,然后观察 IDEA 和 Maven 的测试输出,看看错误信息是如何帮助你定位问题的。

有了单元测试的保护,你的代码质量就有了坚实的基础。下一篇文章,我们将学习日志框架——如何在程序中优雅地记录运行信息,方便问题排查和监控。

我们下一篇见。😃

📌 获取本系列示例代码请访问 GitCode。

Junit Mock 单元测试 实战总结 Junit Mock 单元测试 实战总结 一、maven依赖 <!-- test --> <junit.version>4.12</junit.version> <jetty.version>8.1.10.v20130312</jetty.version> ... 阅读详情

相关推荐

Java笔记 JUnit实现自动化单元测试

Java笔记 JUnit实现自动化单元测试一、JUnit的基本概念1.JUnit简介2.PackageJUnit的配置二、JUnit测试用例中元素的简单说明1.@Test2.assert断言方法三、具体测试用例浅析1.Example 12.Example 2 (more complex) 一、JUnit的基本概念 1.JUnit简介 JUnit是java语言中非常热门的一个单元测试的框架 2.Package junit.framework ---------- for JUnit3.8 org.junit

YYF_Tommy的博客 1357

Spring Boot 单元测试:JUnit 5 + Mockito 基础用法

本文系统地介绍了如何利用 JUnit 5 和 Mockito 为 Spring Boot 应用编写高效的单元测试。我们学习了其核心注解(@Mock)、核心方法(verify)以及 AAA(Arrange-Act-Assert)测试模式。单元测试的核心是隔离,使用@Mock来模拟依赖。简化了依赖注入的设置。AAA 模式为编写结构化的测试提供了清晰的蓝图。Stubbing (用于控制输入,verify用于验证行为。AssertJ提供了卓越的断言体验。

走向CTO的路上... 1954

树莓派IgH EtherCAT主站部署与实时内核调优实战

本文详细介绍了在树莓派上部署开源IgH EtherCAT主站并进行实时内核调优的完整实战流程。通过编译实时内核(RT-Preempt)、交叉编译IgH主站、系统集成配置及性能优化,实现了低成本、高定制的工业控制解决方案,有效满足了EtherCAT通信对微秒级实时性的严苛要求。

weixin_29166013的博客 299

【Spring框架】单元测试:JUnit

单元测试:JUnit 在之前的测试方法中,几乎都能看到以下的两行代码: ApplicationContext context = new ClassPathXmlApplicationContext("xxx.xml"); Xxxx xxx = context.getBean(Xxxx.class); 这两行代码的作用是创建Spring容器,最终获取到对象,但是每次测试都需要重复编写。针对上述问题,我们需要的是程序能自动帮我们创建容器。我们都知道JUnit无法知晓我们是否使用了 Spring 框架,更不用

鱼干的博客 3719

.NET+Vue企业级RBAC权限平台:开箱即用的生产就绪方案

RBAC(基于角色的访问控制)是企业系统安全治理的基础模型,其核心在于将用户、角色与权限解耦,通过动态能力组合实现细粒度管控。在真实工程中,RBAC需突破静态角色限制,支持时间维度授权、前后端双重鉴权、行级数据范围控制等关键能力。本文聚焦于一套已落地金融、政务、制造等多行业的生产级实现——基于.NET Minimal API与Vue 3的前后端分离架构,提供菜单/按钮/接口/数据四层权限控制,内置滑动过期JWT、Redis权限缓存、动态路由加载与权限指令等开箱即用能力,显著降低权限配置与审计成本。

weixin_33326218的博客 274

Java的JUnit单元测试

导入jar包,测试方法上必须使用 @Test 进行修饰, 测试方法必须使用 public void 进行修饰,不能带任何的参数。测试单元中的每个方法必须可以独立测试,测试方法间不能有任何的依赖...

Steven的博客 2405

用STM32手搓一个体温计

市面上大多额温计、测温计精度。

m0_61687959的博客 2375

在Eclipse中使用JUnit进行单元测试

JUnit是什么? JUnit的官网给出的简介: JUnit is a simple framework to write repeatable tests. It is an instance of the xUnit architecture for unit testing frameworks. 每编写完一个函数之后,都应该对这个函数的方方面面进行测试,这样的测试我们称之为单元测试。JUn...

xyzhang的博客 4432

基于FPGA与红外成像的眼动追踪系统设计与实现(教学向)

本文详细介绍了基于FPGA与红外成像的眼动追踪系统设计与实现。通过红外摄像头采集图像,利用FPGA进行实时图像处理和红外瞳孔追踪,结合Verilog编程实现多目标检测与瞳孔定位。该系统适用于嵌入式视觉教学,展示了硬件搭建、算法优化及实时显示的完整流程。

g5h6i7j的博客 823

极验第四代滑块验证码破解(三):滑块轨迹构造

极验第四代滑块验证码破解(三):滑块轨迹构造声明 声明 原创文章,请勿转载! 本文内容仅限于安全研究,不公开具体源码。维护网络安全,人人有责。 本文关联文章超链接:

帯泪的鱼的博客 8623

实训报告4:JUnit单元测试实训

本次JUnit单元测试针对Triangle类进行了全面验证,涵盖三角形类型判断、面积周长计算等功能。在测试过程中,发现边长3-4-8的用例被误判为一般三角形,经分析原因为逻辑运算符使用错误(||应改为&&)。修正后所有测试通过,包括等边、等腰、直角等7种情况的正确识别以及计算功能验证。该实训有效提升了白盒测试能力,验证了JUnit框架在自动化测试中的实用性,同时强调了边界条件检查和逻辑严谨性的重要性。

2401_83578994的博客 1038

详解Nacos集群搭建

在我们日常的开发当中,用的都是单点Nacos,这种模式,我们自己开发测试玩一玩还可以,但是到了企业的生产环境之下,你还这么玩的话,那肯定是要出大问题了。因为在企业当中,我们更加强调的是高可用,所以在企业的生产环境下,Nacos一定要做成个集群。

博客 1万+

单元测试(JUnit)

JUnit 是 Java 社区中最流行的单元测试框架之一。它是一个开源框架,用于编写和运行可重复的测试。JUnit 促进了“测试先行”(test-first)的开发模式,并提供了一个丰富的注解和断言库来测试代码的不同方面。它是测试驱动开发(TDD)和行为驱动开发(BDD)实践的基础工具。JUnit 版本JUnit 有几个重...

cnzzs的博客 420

从 AI 助手到 ADT 自动化桥梁:全面解析 Vibing Steampunk 的定位、能力边界与典型使用场合

Vibing Steampunk是一个面向SAP ABAP开发的AI自动化工具集,它通过ADT API将SAP开发能力系统化地暴露给AI助手和命令行工作流。该工具支持ECC、S/4HANA等所有启用ADT的系统,提供代码读取、修改、测试、调试等全流程自动化能力。核心功能包括AI调试、上下文压缩、ABAP语言服务、Lua脚本自动化等,并内置多重安全控制。其分层架构兼容标准ADT和WebSocket扩展,既适合AI驱动开发,也支持传统DevOps自动化,特别适用于老系统代码考古、知识接力和复杂问题诊断场景。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 150

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

软件测试-Junit单元测试工具

JUnit是一个非常有用的单元测试框架,它可以帮助我们快速地编写和运行可重复的测试用例。在使用JUnit时,我们需要注意以下几点:

LITTLE0BOY的博客 1235

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

头歌-Junit单元测试

【代码】头歌-Junit单元测试。

weixin_74284876的博客 2461

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

spring 单元测试 Junit

spring 单元测试 Junit

南城余coding的博客 1264

JUnit单元测试

测试方法又分为:白盒,黑盒,灰盒测试

2401_87092242的博客 405

wvp-GB28181-pro单元测试:基于JUnit的服务层测试实践

在安防监控领域,GB28181协议设备的稳定性直接关系到视频流传输、设备控制等核心功能的可靠性。wvp-GB28181-pro作为开源的GB28181平台实现,其服务层(Service Layer)承担着设备管理、用户认证、媒体流处理等关键业务逻辑。然而通过对项目结构的分析发现,核心服务如`UserService`、`DeviceService`等均缺乏对应的单元测试覆盖,这可能导致: - 设备...

gitblog_00027的博客 1172

spring6:6、单元测试:JUnit

这两行代码的作用是创建Spring容器,最终获取到对象,但是每次测试都需要重复编写。针对上述问题,我们需要的是程序能自动帮我们创建容器。我们都知道JUnit无法知晓我们是否使用了 Spring 框架,更不用说帮我们创建 Spring 容器了。Spring提供了一个运行器,可以读取配置文件(或注解)来创建容器。我们只需要告诉它配置文件位置就可以了。这样一来,我们通过Spring整合JUnit可以使程序创建spring容器了。JUnit4在公司也会经常用到,在此也学习一下。搭建spring-junit模块。

该博主太懒了,简介都不写 730

测试工程师必须要知道的单元测试框架Junit详解_junit5测试套件 @runwith(1)

现在我也找了很多测试的朋友,做了一个分享技术的交流群,共享了很多我们收集的技术文档和视频教程。而且还有很多在自动化,性能,安全,测试开发等等方面有一定建树的技术大牛。System.out.println(“test1方法…System.out.println(“test2方法…System.out.println(“测试类1”);System.out.println(“测试类2”);qq群号:310357728【暗号:csdn999】分享他们的经验,还会分享很多直播讲座和技术沙龙。//这里有很多个测试类。

2401_84562529的博客 937

java junit4 for_使用JUnit4进行java单元测试

第一步:创建一个java工程,在工程中创建一个被单元测试的Student数据类,代码如下:1 packagecom.junittest.yu;23 public classStudent4 {5 privateString name;6 privateString sex;7 private inthigh;8 private intage;9 privat...

weixin_29306571的博客 470

JUnit5测试框架

JUnit5是JUnit框架的最新版本,基于和三个模块构成。JUnit5引入了一些令人兴奋的新特性,支持Lambda表达式、扩展模型、动态测试等。

dl_dabai的博客 1290
上一篇: 55. 【Java】Maven:项目构建的“管家”
下一篇: 57. 【Java】日志框架:SLF4J与Logback
gugucoding
博客等级 码龄140天 7粉丝 102原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值