测试理念

正确性工具#1:自动分级器

自动评分器可能是您接触到的第一个正确性工具。事实上,CS61B的自动分级器是基于 JUnit 加上一些额外的自定义库。

对自动分级者有一些很大的好处。也许最重要的是,它可以为您验证正确性,使您免于编写所有测试的繁琐且无指导性的任务。它还通过提供多汁的分数作为实现正确性的激励,使评估过程游戏化。如果学生花费过多的时间追逐实际上不会影响他们的成绩或学习的最终分数,这也可能适得其反。

然而,自动分级器在现实世界中并不存在,依赖自动分级器会养成坏习惯。偶尔上传代码并等待自动评分器运行会阻碍一个人的工作流程。Autograder Driven Development 是一个极端版本,学生编写所有代码,修复编译器错误,然后提交给自动评分器。在得到错误后,学生可以尝试进行一些更改,在打印语句中撒上一些,然后再次提交。并重复。最终,如果您依赖自动评分器,则无法控制工作流或代码。

正确性工具 #2:JUnit 测试

正如我们所看到的,JUnit 测试为您打开了一个新世界。您无需依赖其他人编写的自动评分器,而是为程序的每个部分编写测试。我们将这些部分中的每一个都称为一个单元。这使您可以对代码的每个单元充满信心 - 您可以依赖它们。这也有助于减少调试时间,因为您可以一次将注意力隔离到一个代码单元(通常是单个方法)。单元测试还迫使您明确每个代码单元应该完成什么。

但是,单元测试也有一些缺点。首先,编写全面的测试需要时间。编写不完整的单元测试很容易,这会给代码带来错误的信心。为依赖于其他单元的单元编写测试也很困难(考虑 your LinkedListDequeaddFirst 的方法)。

*测试驱动开发 (TDD)*

TDD 是一个开发过程,在这个过程中,我们在编写代码本身之前为代码编写测试。步骤如下:

  1. 确定新功能。
  2. 为该功能编写单元测试。
  3. 运行测试。它应该失败。
  4. 编写通过测试的代码。
  5. 可选:重构代码以使其更快、更简洁等。除了现在我们有一个应该通过的测试的参考。

image-20240119190920106

正确性工具#3:集成测试

单元测试很棒,但我们也应该确保这些单元能够正常工作(与这个模因不同)。集成测试验证组件是否正确地交互在一起。JUnit 实际上可以用于此目的。你可以把单元测试想象成最细微的,而集成测试的抽象级别高于此。

集成测试的挑战在于,手动操作很繁琐,但自动化却具有挑战性。在高度抽象的层次上,很容易错过细微或罕见的错误。

JUnit 测试

Assert (JUnit API)

虽然 JUnit 确实改进了一些东西,但我们之前的测试代码在几个方面有点笨拙。在本节的其余部分,我们将讨论您可以进行的两个主要增强功能,以便您的代码更简洁、更易于使用。从语法的角度来看,这些增强功能看起来非常神秘,所以只需复制我们现在正在做的事情,我们将在后面的章节中解释其中的一些(但不是全部)。

第一个增强功能是使用所谓的“测试注释”。为此,我们:

  • 在每个方法前面加上 @org.junit.Test (不带分号)。
  • 将每种测试方法更改为非静态。
  • 从类中删除 TestSort 我们 main 的方法。

第二个增强功能将允许我们为一些非常长的方法名称以及注释名称使用较短的名称。具体来说,我们将使用所谓的“import 语句”

不同与Python, import语句后要加分号

我们首先将 import 语句 import org.junit.Test; 添加到文件的顶部。完成此操作后,我们可以简单地将 的所有 @org.junit.Test 实例替换为 @Test .

然后,我们添加第二个 import 语句 import static org.junit.Assert.* 。这样做之后,我们可以省略任何我们拥有的 org.junit.Assert. .例如,我们可以简单地替换为 org.junit.Assert.assertEquals(expected2, actual2); assertEquals(expected2, actual2);

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
import static org.junit.Assert.*;
import org.junit.Test;
public class TestSort {
//导入包前为@org.junit.Test
@Test
public void testFindSmallest() {
String[] input = {"i", "have", "an", "egg"};
String expected = "an";
String actual = Sort.findSmallest(input);
assertArrayEquals(expected, actual);
//导入前为org.junit.Assert.assertArrayEquals(expected, actual);
}
}