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日

相关文章

  • java开发之闹钟的实现代码

    下面是“Java开发之闹钟的实现代码”完整攻略: 一、准备工作 确定闹钟的功能需求,如:设定时间,响铃提示等; 选定合适的Java开发IDE,如Eclipse或IntelliJ IDEA; 确定使用的Java版本,本项目中使用Java 8。 二、项目搭建 新建Java项目,并创建一个Clock类; 创建一个定时器Timer,并设定定时任务,如下: timer…

    Java 2023年5月19日
    00
  • jquery自定义下拉列表示例

    下面我来详细讲解一下“jQuery自定义下拉列表”的制作方法。 1. 简介 自定义下拉列表可以提升页面的交互体验,并且可以使页面更加美观。本文将使用jQuery来创建自定义下拉列表,包括如何使用HTML、CSS和JavaScript来实现。 2. 实现过程 下面我们以两个示例来详细讲解如何实现自定义下拉列表。 示例一 在这个示例中,我们将使用一个普通的&lt…

    Java 2023年5月19日
    00
  • servlet实现文件上传与下载功能

    实现文件上传和下载功能是Web开发中比较常见的需求,其中使用Servlet技术是一种比较常用的方式。下面我将从Servlet的角度详细讲解如何实现文件上传和下载功能。 文件上传 1. 创建 HTML 表单 我们需要在 HTML 表单中添加 <input> 标签,然后设置 type 属性为 file,即可实现文件上传功能。 <form act…

    Java 2023年6月15日
    00
  • 浅谈Spring Boot Web 应用性能优化

    浅谈Spring Boot Web 应用性能优化 Spring Boot是一个非常流行的Java Web框架,它提供了很多便利的功能,但是在实际应用中,我们也需要考虑性能问题。本文将介绍一些Spring Boot Web应用性能优化的技巧和方法。 1. 使用缓存 缓存是提高Web应用性能的一种常用方法。Spring Boot提供了多种缓存解决方案,包括Ehc…

    Java 2023年5月18日
    00
  • 如何检查线程状态?

    以下是关于如何检查线程状态的完整使用攻略: 如何检查线程状态? 在 Java 中,可以使用 Thread 类的 getState() 方法来获取线程的状态。该方法返回一个 Thread.State 枚举类型的值,表示线程的状态。 示例一:使用 getState() 方法获取线程状态。可以使用以下代码实现: public class MyThread exte…

    Java 2023年5月12日
    00
  • 从字符串中截取等长字节的Java代码

    要从Java字符串中截取等长字节,我们可以使用Java内置的getBytes()方法。getBytes()方法可以将字符串转换为字节数组,我们可以根据需要从数组中截取所需的字节。 下面是截取等长字节的Java代码攻略: 1.首先,我们需要将字符串转换为字节数组,使用getBytes()方法,可以将字符串转换为字节数组。 String str = "…

    Java 2023年5月27日
    00
  • 举例讲解Java的JSON类库GSON的基本用法

    下面就给您详细讲解Java的JSON类库GSON的基本用法的攻略。 什么是GSON GSON是Google开发的用于Java解析JSON数据的类库。它可以将一个JSON字符串转化成Java对象,同样也可以将Java对象转化成对应的JSON字符串。GSON可以编码和解码任何Java对象。 导入GSON的Jar包 在使用GSON之前,我们需要先在项目中导入GSO…

    Java 2023年5月26日
    00
  • 垃圾收集器接口的作用是什么?

    以下是关于垃圾收集器接口的详细讲解: 什么是垃圾收集器接口? 垃圾收集器接口是 Java 虚拟机提供的一组接口,用于实现自定义的垃圾收集器。通过实现垃圾收集器接口,可以自定义垃圾收集器的行为和策略,以满足不同的应用场景和需求。 垃圾收集器接口包括以下几个接口: Collector:垃圾收集器接口,定义了垃圾收集的基本行为和策略。 MemoryPoolMXBe…

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