java程序员如何编写更好的单元测试的7个技巧

下面是针对"Java程序员如何编写更好的单元测试的7个技巧"的一份攻略。

技巧1:拆分单元测试

单元测试应该足够小,以至于一个单元测试只需要测试一个方法或函数。这样使得测试容易重复、快速执行和简单调试。拆分单元测试也使测试更精确,因为每个单元测试只测试一个输入和输出组合。

示例:

以下是一个简单的 Java 类,将两个整数相加并返回结果:

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

对于此类,将它拆分成两个单元测试,一个测试方法参数都为正数的情况,另一个测试方法参数一个为正数一个为负数的情况:

@Test
public void testAddition_positiveNumbers() {
    int result = Addition.add(2, 4);
    assertEquals(6, result);
}

@Test
public void testAddition_mixedNumbers() {
    int result = Addition.add(2, -4);
    assertEquals(-2, result);
}

技巧2:引入测试数据工厂

在编写单元测试时,我们需要为每个测试方法提供各种输入,并检查其输出。如果您手动编写每个测试用例,这将非常困难和耗费时间。测试数据工厂是测试单元函数时的好伙伴。它内置于测试库中,其中包含一些基本的测试函数和生成测试数据的工具类。

示例:

以下是一个 Java 类,将两个字符串连接在一起并返回结果:

public class Concatenation {
    public static String concat(String a, String b) {
        return a + " " + b;
    }
}

下面是一个使用 Junit5 @ParameterizedTest 注释和 ArgumentsProvider 接口的示例,编写了一个 Factory 类为此类提供测试数据:

public class ConcatenationTest {

    @ParameterizedTest
    @ArgumentsSource(ConcatenationFactory.class)
    void should_concatenate_strings(final String a, final String b, final String expected) {
        final String result = Concatenation.concat(a, b);
        assertEquals(expected, result);
    }

    private static class ConcatenationFactory implements ArgumentsProvider {
        @Override
        public Stream<? extends Arguments> provideArguments(final ExtensionContext extensionContext) {
            return Stream.of(
                Arguments.of("Hello", "world", "Hello world"),
                Arguments.of("JUnit5", "is awesome", "JUnit5 is awesome"),
                Arguments.of("", "", " ")
            );
        }
    }
}

技巧3:使用行为驱动测试

在单元测试中,最好使用行为驱动测试(BDD)或使用 AssertJ 等库的断言来描述测试。使用 BDD,您可以清楚地表达正在测试的行为或功能,并且确保测试的理解和可读性。

示例:

下面是一个使用 AssertJ 的 BDD 风格的示例:

@Test
void whenSalaryIsLessThanThreshold_outputIsZero() {
    // Given
    int salary = 20_000;
    // When
    int tax = calculateTax(salary);
    // Then
    assertThat(tax).isZero();
}

@Test
void whenSalaryIsGreaterThanThreshold_outputIsGreaterThanZero() {
    // Given
    int salary = 70_000;
    // When
    int tax = calculateTax(salary);
    // Then
    assertThat(tax).isGreaterThan(0);
}

技巧4:使用 MockObject 或 Stubbing 单元测试

在单元测试中,您必须仅测试功能模块。但是,如果模块依赖于其他模块,则必须针对其依赖项运行测试,并使用 MockObject 或 Stubbing 技术,该技术允许您在不执行外部依赖项的情况下测试。它有助于减少测试运行时间并提高测试速度。

示例:

以下类使用一个 GreetingsService 类,用于获取问候语并添加到消息中:

public class MessageService {

    private final GreetingsService greetingsService;

    public MessageService(final GreetingsService greetingsService) {
        this.greetingsService = greetingsService;
    }

    public String getMessage(final String name) {
        final String greeting = greetingsService.getGreeting(name);
        return "Hello, " + name + "! " + greeting;
    }

}

在以下测试中,我们使用 Mockito 来模拟 GreetingsService 的依赖项和 Stubbing:

@Test
void getMessage_ShouldReturnCorrectMessage() {
    final GreetingsService mockedGreetingService = mock(GreetingsService.class);
    final MessageService messageService = new MessageService(mockedGreetingService);

    final String name = "Alice";
    final String expected = "Hello, Alice! good morning";

    when(mockedGreetingService.getGreeting(name)).thenReturn("good morning");

    final String result = messageService.getMessage(name);

    assertThat(result).isEqualTo(expected);
}

技巧5:运行单元测试的多个版本

随着时间的推移,您的代码库可能会发生变化。您应该保持您的测试套件不仅能够运行最新版本的代码,也要能够运行先前版本的代码。创建多个分支,每个分支对应于一个版本的代码,以确保它们仍容易编译,运行以及产生正确的结果。

示例:

假设我们有一个简单的 Java 类,将两个整数相加并返回值:

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

我们需要在代码库多个版本中运行测试。使用 Maven 的 profile 功能,您可以轻松地在支持的不同版本中运行测试,如下面的示例:

<profiles>
    <profile>
        <id>jdk11</id>
        <activation>
            <jdk>11</jdk>
        </activation>
        <build>
            <plugins>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>3.0.0-M4</version>
                    <configuration>
                        <argLine>--illegal-access=deny</argLine>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
    <profile>
        <id>jdk8</id>
        <activation>
            <jdk>1.8</jdk>
        </activation>
        <build>
            <plugins>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.2</version>
                    <configuration>
                        <argLine>--illegal-access=permit</argLine>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

技巧6:编写可读的单元测试

当您编写可读性差的测试时,您很难理解测试的意图。同时,当测试失败时,您需要知道出现了哪种问题,而可读性差的测试将会使问题更加难以定位。为了测试易读性,您可以编写代码注释、使用描述性的变量名、等等。

示例:

以下是一个使用 Junit5 和 AssertJ 的示例,它禁用了测试方法。使用注释和描述性变量名称,提高了测试可读性:

@Disabled("needs to be refactored")
@Test
void calculatingTaxForPersonThatMakesLessThan16k_shouldReturnZero() {
    final int personSalary = 12_000;
    final int personAge = 40;
    final String personName = "John Doe";

    final Person person = new Person(personName, personAge, personSalary);
    final int result = taxCalculator.calculate(person);

    assertThat(result).isEqualTo(0);
}

技巧7:在IDE中运行单元测试

在 IDE 中遵循 TDD(测试驱动开发)流程,可以让您快速反馈并调试功能问题,而不必延迟到将代码提交到代码库中后检查问题。许多 IDE 都支持单击按钮即可运行单元测试。

示例:

当使用 IntelliJ IDEA 编辑器时,点击 Test 按钮或使用快捷键 Ctrl + Shift + F10 即可运行单元测试。如果您更改代码,并保存文件,IntelliJ IDEA 将自动重新运行相关测试。

这就是“Java程序员如何编写更好的单元测试的7个技巧”的攻略,希望对您的测试工作有所帮助!

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java程序员如何编写更好的单元测试的7个技巧 - Python技术站

(0)
上一篇 2023年5月20日
下一篇 2023年5月20日

相关文章

  • Spring Security基本架构与初始化操作流程详解

    Spring Security基本架构与初始化操作流程详解 介绍 Spring Security是一个基于Spring框架的安全性框架,处理了身份认证(authentication)与授权(authorization)等一系列的安全性问题,能够使我们更快更简单地集成到Spring应用程序中,保障应用程序的安全性。 本篇文章将会为您详细介绍Spring Sec…

    Java 2023年6月3日
    00
  • java实现大数加法(BigDecimal)的实例代码

    下面就是详细讲解“java实现大数加法(BigDecimal)的实例代码”的完整攻略: 1. 简介 在 Java 中,整数类型有其上限和下限,如果数值超出其范围,就会产生溢出,导致计算结果不正确。 为了解决这个问题,我们可以使用 BigDecimal 类型来进行大数值的加、减、乘、除运算,以确保计算的精确性。 2. 引入 BigDecimal 类 要使用 B…

    Java 2023年5月19日
    00
  • java实现的简单猜数字游戏代码

    下面是详细讲解 “Java实现的简单猜数字游戏代码” 的攻略: 思路 该猜数字游戏的思路如下:1. 系统随机生成一个数字。2. 玩家输入一个数字。3. 系统比较玩家输入的数字和系统生成的数字,提示玩家输入数字是大于还是小于系统生成的数字。4. 重复第2步和第3步,直到玩家猜中系统生成的数字。 代码实现 下面是代码实现的步骤: 步骤1: 导入所需的库和包 im…

    Java 2023年5月23日
    00
  • Java实现单人信息管理程序

    下面我将为你详细讲解“Java实现单人信息管理程序”的完整攻略。 1. 需求分析 在开始编写程序之前,我们需要确定具体的需求。本文中,我们需要实现单人信息管理程序,需要实现以下功能:1. 添加一个新的信息2. 查看所有信息3. 修改已有的信息4. 删除已有的信息 2. 数据结构设计 在确定需求之后,我们需要确定数据结构。这里我们使用Java中的ArrayLi…

    Java 2023年5月18日
    00
  • java简单解析xls文件的方法示例【读取和写入】

    Java简单解析XLS文件的方法示例:读取和写入 1. 概述 XLS是一种Microsoft Excel电子表格文件格式,是常见的办公文档,需要在Java程序中对其进行处理和解析。本文将介绍Java中读取和写入XLS文件的方法,包括使用Apache POI库读取和写入XLS文件。 2. 使用Apache POI库读取XLS文件 Apache POI是一款用于…

    Java 2023年5月20日
    00
  • php中stream(流)的用法

    关于PHP中stream(流)的用法,我们可以从以下三个方面入手讲解:流的概念、流的类型和流的用法。 一、流的概念 流,是指将二进制数据按照某种规则组织在一起的数据流,这种数据流一般来说是顺序读写的。 二、流的类型 PHP中stream主要有四种类型,分别是:文件流、数据流、网络流、过滤流。 文件流 文件流就是对文件进行读取和写入数据。在PHP中,PHP中f…

    Java 2023年5月23日
    00
  • Java基础类学习之String详解

    Java基础类学习之String详解 1. 什么是String String是Java语言中常用的引用类型,代表一个字符串对象。在Java程序中,我们可以通过创建String对象的方式或者直接赋值的方式来定义一个String类型的变量。 // 创建String对象 String str1 = new String("Hello World&quot…

    Java 2023年5月26日
    00
  • VScode+Java配置与使用的详细步骤

    下面我将为您讲解“VScode+Java配置与使用的详细步骤”,主要包括以下几个步骤: 安装JDK并添加环境变量 安装VScode及必要的插件 创建Java项目并编辑代码 调试Java代码 接下来,我将一步步为您详细介绍。 1. 安装JDK并添加环境变量 Java需要使用JDK才能进行开发,因此我们首先需要安装Java Development Kit(JDK…

    Java 2023年5月26日
    00
合作推广
合作推广
分享本页
返回顶部