1

我正在使用 JUnit 框架从 Java 中的某种编程语言为解释器编写测试。为此,我创建了大量的测试用例,其中大多数包含正在测试的语言的代码片段。由于这些片段通常很小,因此将它们嵌入到 Java 代码中很方便。但是,Java 不支持多行字符串文字,由于转义序列和拆分较长字符串文字的必要性,这使得代码片段有点模糊,例如:

String output = run("let a := 21;\n" +
                    "let b := 21;\n" +
                    "print a + b;");
assertEquals(output, "42");

理想情况下,我想要类似的东西:

String output = run("""
    let a := 21;
    let b := 21;
    print a + b;
""");
assertEquals(output, "42");

一种可能的解决方案是将代码片段移动到外部文件,并从相应的测试用例中引用每个文件。然而,这增加了显着的维护负担。

另一种解决方案是使用不同的 JVM 语言(例如支持多行字符串文字的 Scala 或 Jython)来编写测试。这将为项目添加一个新的依赖项,并且需要移植现有的测试。

有没有其他方法可以在不增加太多维护的同时保持测试代码片段的清晰性?

4

3 回答 3

1

我过去曾这样做过。我做了类似于 home 建议的事情,我使用了包含测试及其预期结果的外部文件,但使用了 @Parameterized 测试运行器。

@RunWith(Parameterized.class)
public class ParameterTest {
    @Parameters
    public static List<Object[]> data() {
        List<Object[]> list = new LinkedList<Object[]>();
        for (File file : new File("/temp").listFiles()) {
            list.add(new Object[]{file.getAbsolutePath(), readFile(file)});
        }

        return list;
    }

    private static String readFile(File file) {
        // read file 
        return "file contents";
    }

    private String filename;
    private String contents;

    public ParameterTest(String filename, String contents) {
        this.filename = filename;
        this.contents = contents;
    }

    @Test
    public void test1() {
        // here we test something
    }

    @Test
    public void test2() {
        // here we test something
    }
}

在这里,我们对 /temp 中的每个文件运行test1()&test2()一次,并带有文件名和文件内容的参数。测试类被实例化并为您添加到使用@Parameters 注释的方法中的列表中的每个项目调用。

使用此测试运行程序,您可以在失败时重新运行特定文件;大多数 IDE 支持重新运行单个失败的测试。@Parameterized 的缺点是没有任何方法可以明智地识别测试,以便名称出现在 Eclipse JUnit 插件中。你得到的只是 0、1、2 等。但至少你可以重新运行失败的测试。

正如 home 所说,良好的日志记录对于正确识别失败的测试和帮助调试非常重要,尤其是在 IDE 之外运行时。

于 2011-10-10T21:25:51.737 回答
1

过去,将测试用例移动到文件中对我有用,它也是一个解释器:

  1. 创建了一个 XML 文件,其中包含要解释的片段以及预期的结果。这是一个相当简单的 XML 定义,一个主要包含testIDvalueexpected resulttype和的测试元素列表description
  2. 恰好实现了一个读取文件并遍历其内容的 JUnit 测试,以防万一失败,我们使用testIDanddescription来记录失败的测试。

这主要是因为我们有一个定义良好的通用接口,就像你的run方法一样,所以重构仍然是可能的。在我们的例子中,这并没有增加维护工作,事实上我们可以通过向 XML 文件中添加更多元素来轻松创建新测试。

也许这不是应该使用单元测试的最佳方式,但它对我们来说效果很好。

于 2011-10-09T07:11:04.187 回答
1

既然您在谈论其他 JVM 语言,您是否考虑过 Groovy?您必须添加外部依赖项,但仅在编译/测试时(您不必将其放入生产包中),并且它提供多行字符串。在您的情况下还有一个主要优势:它的语法向后兼容 Java(这意味着您不必重写测试)!

于 2011-10-09T07:16:30.013 回答