如何编写单元测试?

164

我有一个Java类。我该如何进行单元测试呢?


在我的情况下,我有一个执行二进制求和的类。它接受两个byte[]数组,将它们相加,并返回一个新的二进制数组。


7
您可以使用像 jUnit 这样的工具为您的 Java 类编写测试用例(测试方法)。然后将 jUnit 测试作为构建过程(ant/maven)的一部分来调用。使用 jUnit 并不难,难点在于尽可能想出许多测试场景,以便早早地和经常地捕获漏洞。 - CoolBeans
请在标题中提到 "使用Java"。(目前我无法完成,编辑队列已满) - Valerio Bozz
5个回答

143

我为了IntelliJ和Eclipse两种工具都提供这篇文章。

Eclipse:

若要为您的项目制作单元测试,请按照以下步骤操作(我使用Eclipse来编写此测试):

1- 点击New -> Java Project。

Create Project

2- 输入您的项目名称,然后点击完成。

Create Project

3- 右键单击您的项目。 然后,单击New -> Class。

Create Class

4- 输入您的类名称,然后点击完成。

Create Class

接下来,按照以下方式完成类的编写:

public class Math {
    int a, b;
    Math(int a, int b) {
        this.a = a;
        this.b = b;
    }
    public int add() {
        return a + b;
    }
}

5- 点击 文件(File) -> 新建(New) -> JUnit测试用例(JUnit Test Case)。

Create JUnite Test

6- 选中 setUp() 并点击完成(Finish)。setUp() 将是您初始化测试的地方。

Check SetUp()

7- 点击确定(OK)。

Add JUnit

8- 在此,我只需添加 7 和 10。因此,我期望答案为 17。按照这样的方式完善您的测试类:

import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class MathTest {
    Math math;
    @Before
    public void setUp() throws Exception {
        math = new Math(7, 10);
    }
    @Test
    public void testAdd() {
        Assert.assertEquals(17, math.add());
    }
}

9- 在包资源管理器中右键单击测试类,然后单击“Run as -> JUnit Test”。

Run JUnit Test

10- 这是测试结果。

Result of The Test

IntelliJ: 请注意,我使用的是 IntelliJ IDEA community 2020.1 版本的截图。在执行这些步骤之前,您需要设置好 jre。我正在使用 JDK 11.0.4。

1- 在项目的主文件夹上右键单击->新建 ->目录。您应该将其命名为 'test'。

enter image description here

2- 在 test 文件夹上右键单击并创建适当的包。我建议创建与原始类相同的包名称。然后,您需要在 test 目录上右键单击 ->标记目录为 ->测试源根目录。

enter image description here

3- 在 test 目录的正确包中,您需要创建一个 Java 类(我建议使用 Test.java)。

enter image description here

4- 在创建的类中,键入 '@Test'。然后,在 IntelliJ 给出的选项中,选择将 'JUnitx' 添加到类路径。

enter image description here enter image description here

5- 在测试类中编写测试方法。该方法的签名如下:

@Test
public void test<name of original method>(){
...
}

您可以像下面这样进行断言:

Assertions.assertTrue(f.flipEquiv(node1_1, node2_1));

这些是我添加的导入项:

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

输入图像描述

这是我编写的测试代码: 输入图像描述

你可以按照以下方式检查你的方法:

Assertions.assertEquals(<Expected>,<actual>);
Assertions.assertTrue(<actual>);
...

运行单元测试,请右键点击测试文件,然后选择"Run"。 图片描述

如果您的测试通过,结果将如下所示: 图片描述


140
  1. 定义一个正常情况下,正确输入的期望和所需输出。

  2. 现在,声明一个类来实现测试,可以随意命名(通常为TestAddingModule),并向其中添加testAdd方法(如下所示):

    • 编写一个方法,在其上方添加@Test注释。
    • 在该方法中,运行二进制加法并使用assertEquals(expectedVal,calculatedVal)进行断言。
    • 通过运行测试方法来测试它(在Eclipse中,右键单击,选择Run as → JUnit test)。

      //for normal addition 
      @Test
      public void testAdd1Plus1() 
      {
          int x  = 1 ; int y = 1;
          assertEquals(2, myClass.add(x,y));
      }
      
  3. 根据需要添加其他情况。

    • 测试您的二进制求和在整数溢出时是否会抛出意外异常。
    • 测试您的方法是否优雅地处理空输入(以下是示例)。

      //if you are using 0 as default for null, make sure your class works in that case.
      @Test
      public void testAdd1Plus1() 
      {
          int y = 1;
          assertEquals(0, myClass.add(null,y));
      }
      

  1. @Test 注释是必需的吗?
  2. 为什么不使用 assertNotNull 测试空输入?
  3. 单元测试的结果在哪里捕获?如何向用户指示结果?
- user137717
10
是的,需要使用@Test注解。这是为了告诉单元测试运行器,该方法代表一个单元测试,并应该被执行。没有用@Test注解的方法将不会被测试运行器执行。 - Ali Shah Ahmed
对于第二个测试 - 将 null 添加到 y 中不应该只给出 y 吗? - Adjit
谢谢!我想知道为什么测试方法的修饰符不需要添加 static - Liang Zhang

18

这是一个非常通用的问题,有很多方法可以回答。

如果您想使用 JUnit 创建测试,您需要创建测试用例类,然后创建单个测试方法来测试您要测试的类/模块的特定功能(单个测试用例类通常与要测试的单个“生产”类相关联),并在这些方法中执行各种操作,并将结果与正确的结果进行比较。尤其重要的是尽可能多地尝试覆盖各种情况。

在您的具体示例中,您可以例如测试以下内容:

  1. 两个正数之间的简单相加。将它们相加,然后验证结果是否符合预期。
  2. 一个正数和一个负数之间的加法(返回带有第一个参数符号的结果)。
  3. 一个正数和一个负数之间的加法(返回带有第二个参数符号的结果)。
  4. 两个负数之间的加法。
  5. 导致溢出的加法。

为了验证结果,您可以使用 org.junit.Assert 类中的各种 assertXXX 方法(为方便起见,您可以执行 'import static org.junit.Assert.*')。这些方法测试特定条件并在不通过时使测试失败(可选地带有特定消息)。

在您的案例中,示例测试用例类如下(未定义方法内容):

import static org.junit.Assert.*;

public class AdditionTests {
    @Test
    public void testSimpleAddition() { ... }


    @Test
    public void testPositiveNegativeAddition() { ... }


    @Test
    public void testNegativePositiveAddition() { ... }


    @Test
    public void testNegativeAddition() { ... }


    @Test
    public void testOverflow() { ... }
}

如果您不习惯编写单元测试,而是通过编写临时测试来测试您的代码,然后进行“可视化”验证(例如,您编写了一个简单的主方法,接受使用键盘输入的参数,然后打印出结果 - 然后您继续输入值并自行验证结果是否正确),那么您可以从上述格式开始编写此类测试,并使用正确的assertXXX方法验证结果,而不是手动验证。这样,您可以更轻松地重新运行测试,而不是手动测试。


7
其他答案已经向您展示了如何使用JUnit来设置测试类。JUnit不是唯一的Java测试框架。然而,专注于使用框架的技术细节会削弱应该指导您行动的最重要的概念,因此我将谈论这些概念。
- 测试(所有类型的事物)比较某个东西(被测试系统,SUT)的实际行为与其预期行为。 - 可以使用计算机程序进行自动化测试。由于比较是由一个不灵活且无智能的计算机程序完成的,因此必须精确而明确地知道预期行为。 - 程序或程序部分(类或方法)的预期行为是其规范。因此,测试软件需要您对SUT有一个规范。这可能是显式描述,也可能是您脑海中的隐含规范。 - 因此,自动化单元测试需要对您正在测试的类或方法进行精确而明确的规范。 - 但是,在编写SUT的第一行代码之前,您需要那个规范。因此,测试的一部分实际上在您编写SUT的第一行代码之前就开始了。测试驱动开发(TDD)技术将这个想法推到了极致,并让您在编写要测试的代码之前创建单元
许多初学者在此处发布问题,询问如何测试一些代码,展示代码但未说明该代码的规范。正如这个讨论所显示的,任何人都无法对这样的问题给出一个好的答案,因为最多潜在答复者必须猜测规范,并且可能会猜错。问题的提问者显然没有理解规范的重要性,因此是一个需要在尝试编写一些测试代码之前理解我在这里描述的基本原理的新手。

7

像@CoolBeans提到的那样,可以看看jUnit。这里有一个简短的教程,可帮助您入门jUnit 4.x。

最后,如果您真的想了解更多关于测试和测试驱动开发(TDD)方面的知识,我推荐您阅读Kent Beck的以下书籍:《通过示例学习测试驱动开发》


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接