Java 断言:测试假设

JavaJavaBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

介绍

在本实验中,你将学习 Java 中的断言(assertions)。你将了解如何创建断言以及何时使用它们。断言用于测试代码中的假设,主要在软件的测试阶段使用。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL java(("`Java`")) -.-> java/BasicSyntaxGroup(["`Basic Syntax`"]) java(("`Java`")) -.-> java/ObjectOrientedandAdvancedConceptsGroup(["`Object-Oriented and Advanced Concepts`"]) java(("`Java`")) -.-> java/FileandIOManagementGroup(["`File and I/O Management`"]) java(("`Java`")) -.-> java/SystemandDataProcessingGroup(["`System and Data Processing`"]) java/BasicSyntaxGroup -.-> java/operators("`Operators`") java/BasicSyntaxGroup -.-> java/variables("`Variables`") java/BasicSyntaxGroup -.-> java/switch("`Switch`") java/BasicSyntaxGroup -.-> java/output("`Output`") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/user_input("`User Input`") java/ObjectOrientedandAdvancedConceptsGroup -.-> java/exceptions("`Exceptions`") java/FileandIOManagementGroup -.-> java/files("`Files`") java/SystemandDataProcessingGroup -.-> java/math_methods("`Math Methods`") java/SystemandDataProcessingGroup -.-> java/system_methods("`System Methods`") subgraph Lab Skills java/operators -.-> lab-117470{{"`Java 断言:测试假设`"}} java/variables -.-> lab-117470{{"`Java 断言:测试假设`"}} java/switch -.-> lab-117470{{"`Java 断言:测试假设`"}} java/output -.-> lab-117470{{"`Java 断言:测试假设`"}} java/user_input -.-> lab-117470{{"`Java 断言:测试假设`"}} java/exceptions -.-> lab-117470{{"`Java 断言:测试假设`"}} java/files -.-> lab-117470{{"`Java 断言:测试假设`"}} java/math_methods -.-> lab-117470{{"`Java 断言:测试假设`"}} java/system_methods -.-> lab-117470{{"`Java 断言:测试假设`"}} end

创建一个简单的断言

让我们创建一个简单的断言来测试一个数字是否为偶数。我们将假设这个数字是偶数,并使用一个偶数来编写断言。然后,我们将改变这个数字并运行代码。我们应该会得到一个 AssertionError

public class AssertionsLab {
    public static void main(String[] args) {
        int number = 4;
        assert (number % 2) == 0;
        System.out.println("Number is even");

        // 将 number 变量的值改为奇数
        number = 3;
        assert (number % 2) == 0;
        System.out.println("Number is even");
    }
}

禁用断言

默认情况下,Java 中的断言是禁用的。我们可以通过命令行选项来启用断言。

让我们使用 -ea 选项来启用断言并运行代码。

java -ea AssertionsLab

代码应该会打印 "Number is even",然后抛出一个 AssertionError

现在,让我们使用 -da 选项禁用断言并再次运行代码。

java -da AssertionsLab

代码应该会打印两次 "Number is even",而不会抛出任何异常。

使用断言测试输入

断言也可以用于测试方法的输入。让我们创建一个 divide 方法,该方法接收两个参数并返回第一个参数除以第二个参数的商。我们将假设第二个参数不为零,并创建一个断言来检查这一点。

public class AssertionsLab {
    public static void main(String[] args) {
        int a = 10;
        int b = 5;
        int result = divide(a, b);
        System.out.println("Result: " + result);

        // 将 b 的值改为零
        b = 0;
        result = divide(a, b);
        System.out.println("Result: " + result);
    }

    private static int divide(int a, int b) {
        assert b != 0 : "Cannot divide by zero";
        return a / b;
    }
}

使用断言进行调试和测试

我们可以使用断言进行调试和测试。假设我们有一个程序,它读取文件并返回其中的第一个非零数字。为了测试这个程序,让我们创建一个包含三个数字的输入文件。

echo "0\n3\n0" > input.txt

让我们编写一个程序,读取文件并返回其中的第一个非零数字。然后,我们将创建一个断言来测试程序是否返回了正确的输出。

import java.io.File;
import java.io.FileNotFoundException;
+ import java.util.Scanner;

public class AssertionsLab {
    public static void main(String[] args) throws FileNotFoundException {
        Scanner scanner = new Scanner(new File("input.txt"));
        int number = 0;
        while (scanner.hasNext()) {
            number = scanner.nextInt();
            if (number != 0) {
                break;
            }
        }
        assert number == 3 : "Incorrect number read from file";
        System.out.println("First non-zero number: " + number);
    }
}

何时不应使用断言

断言不适合用于验证公共方法的参数。这些断言在运行时可能会被禁用,从而导致意外行为。

public class AssertionsLab {
    public static void main(String[] args) {
        int negativeNumber = -1;
        printPositiveNumber(negativeNumber);
    }

    public static void printPositiveNumber(int number) {
        assert (number > 0) : "Not a valid positive number";
        System.out.println("Positive number: " + number);
    }
}

使断言更具信息性

我们可以为断言添加信息性消息,使其更具信息性,并在失败时提供更好的反馈。现在我们将修改之前代码中的断言,以包含一条信息性消息。

public class AssertionsLab {
    public static void main(String[] args) {
        int number = -1;
        assert (number > 0) : "Negative number found";
        System.out.println("Number is positive: " + number);
    }
}

当代码执行时,消息 "Negative number found" 将会显示。

防止断言破坏代码

断言的主要目的是在测试软件时发现错误。然而,如果断言本身破坏了代码,那就会成为问题。例如,瞬态网络错误或系统上的时序问题可能导致断言失败。此外,如果我们使用断言来验证公共方法的输入,我们可能会让系统面临无效和恶意输入的风险。

避免断言负面影响的一种方法是谨慎使用它们。仅在那些在良好设计的系统中永远不应该发生的情况下使用断言。

public class AssertionsLab {
    public static void main(String[] args) {
        double result = squareRoot(4);
        System.out.println("Square root: " + result);

        double negativeNumber = -4;
        result = squareRoot(negativeNumber);
        System.out.println("Square root: " + result);
    }

    public static double squareRoot(double number) {
        assert number >= 0 : "Number should be non-negative";
        return Math.sqrt(number);
    }
}

避免副作用

在使用断言时,避免副作用非常重要。我们应该避免在断言中修改变量。相反,表达式应仅用于检测问题情况并提供更多诊断信息。

public class AssertionsLab {
    public static void main(String[] args) {
        int firstNumber = 1;
        int secondNumber = 2;
        assert (firstNumber = secondNumber) == 0 : "Values are not equal";
        System.out.println("Values are equal");
    }
}

使用断言检查 Switch 语句

我们可以使用断言来检查 switch 语句是否覆盖了所有可能的情况。让我们创建一个 switch 语句,根据数字返回对应的星期名称。我们假设数字在 0 到 6 的范围内,并创建一个断言来检查这一点。

public class AssertionsLab {
    public static void main(String[] args) {
        int dayNumber = 2;
        String day = getDayName(dayNumber);
        System.out.println("Day: " + day);

        // set dayNumber to an invalid number
        dayNumber = 10;
        day = getDayName(dayNumber);
        System.out.println("Day: " + day);
    }

    public static String getDayName(int dayNumber) {
        String day;
        switch (dayNumber) {
            case 0:
                day = "Sunday";
                break;
            case 1:
                day = "Monday";
                break;
            case 2:
                day = "Tuesday";
                break;
            case 3:
                day = "Wednesday";
                break;
            case 4:
                day = "Thursday";
                break;
            case 5:
                day = "Friday";
                break;
            case 6:
                day = "Saturday";
                break;
            default:
                assert false : "Invalid day number";
        }
        return day;
    }
}

总结

恭喜!你已经完成了 Java 断言实验。你可以在 LabEx 中练习更多实验来提升你的技能。

您可能感兴趣的其他 Java 教程