首页 · ← SuperJ 手册 中文|EN

编写与运行测试

SuperJ 有两种测试机制。本指南覆盖两者,但大多数 SDK 与应用测试使用第一种。

单元测试sj.testGolden-output 测试
位于test/examples/
你编写Asserts.*@Test 方法一个会打印的程序,加上 expected_<name>.txt
运行方式superj test(自托管)superj golden examples(自托管)
通过意味着每个断言都成立(退出码 0)stdout 与期望文件逐字节匹配
用于库/逻辑检查 — map、解析器、数学、池SPEC 一致性、代码生成输出、"打印结果就是规格"

经验法则:如果你会用 assertEquals,就写单元测试;如果你会 println 然后目测结果,就写 golden 测试。


sj.test 做单元测试

第一个测试

test/ 下创建一个以 Test.sj 结尾的文件,标记 // UNIT,并编写 @Test static void 方法。无需 main,无需注册 — 编译器自动接线:

// UNIT
import sj.util.IntArrayList;
import sj.test.Asserts;

class IntArrayListTest {
    @Test
    static void startsEmpty() {
        IntArrayList list = new IntArrayList();
        Asserts.assertTrue("new list is empty", list.isEmpty());
        Asserts.assertEquals("size", 0, list.size());
    }

    @Test
    static void addAndGet() {
        IntArrayList list = new IntArrayList();
        list.add(10);
        list.add(20);
        Asserts.assertEquals("size", 2, list.size());
        Asserts.assertEquals("first", 10, list.get(0));
    }
}

运行它:

superj test             # 构建编译器 + SDK,然后运行每个 test/ 套件

输出:

test IntArrayListTest.startsEmpty ... ok
test IntArrayListTest.addAndGet ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 filtered out

规则

断言 — sj.test.Asserts

全部为 static,消息在前,失败时抛出 AssertionFailure(消息打印在 FAILED 行下方):

方法备注
assertTrue(msg, cond) / assertTrue(cond)
assertFalse(msg, cond) / assertFalse(cond)
assertEquals(msg, expected, actual)intlongbooleandoubleStringObject(通过 .equals)的重载
assertEquals(msg, expected, actual, epsilon)double 在容差范围内 — 用于计算出的浮点数
assertNotEquals(msg, unexpected, actual)intlong
assertNull(msg, value) / assertNotNull(msg, value)
fail(msg)无条件失败
capture(TestCase body)Throwable运行 body,返回它抛出的内容(或 null)— 用于异常测试

测试某物会抛出

无反射:capture() 运行一个 body 并把它抛出的东西交给你,然后你用 instanceof 检查。body 是一个指向非 @Test 辅助方法的方法引用。

class PoolTest {
    @Test
    static void rejectsNull() {
        Throwable t = Asserts.capture(PoolTest::offerNull);
        Asserts.assertTrue("throws IAE", t instanceof IllegalArgumentException);
    }

    static void offerNull() {           // 辅助方法 — 无 @Test
        new ObjectPool<Box>(2, null).offer(null);
    }
}

跳过测试 — @Ignore

@Ignore(与 @Test 一起)以搁置一个已知失败或不稳定的测试。它被报告为 ... ignored,从不运行,且绝不算作失败

@Test
@Ignore
static void flakyUntilFixed() {
    Asserts.assertEquals("known bad", 1, 2);   // 被跳过 — 套件保持绿色
}
test SomeTest.flakyUntilFixed ... ignored
test result: ok. 4 passed; 0 failed; 1 ignored; 0 filtered out

@Ignore 不带 @Test 是编译错误。

A/B 差分测试

没有专门特性 — 在一个 @Test 中计算一个参考(oracle)结果与优化后/真实结果,然后在多个输入上 assertEquals 它们。示例:一个插入排序 oracle 与 SDK 的 Arrays.sort 在带种子的随机数组上对比(见 test/SortDifferentialTest.sj):

@Test
static void arraysSortMatchesReference() {
    Random rng = new Random(12345L);
    for (int trial = 0; trial < 500; trial = trial + 1) {
        int n = rng.nextInt(64);
        int[] data = new int[n];
        for (int i = 0; i < n; i = i + 1) data[i] = rng.nextInt(1000) - 500;
        int[] expected = referenceSort(data);          // A: 平凡正确的 oracle
        int[] actual = new int[n];                      // B: 被测路径
        System.arraycopy(data, 0, actual, 0, n);
        Arrays.sort(actual);
        for (int i = 0; i < n; i = i + 1)
            Asserts.assertEquals("trial " + trial + " idx " + i, expected[i], actual[i]);
    }
}

运行测试

superj test                             # 标准门禁:构建 + 运行全部 test/
./tools/superj test                     # 同上,若编译器 + SDK 已构建(目录默认为 test/)
./tools/superj test test --filter pool  # 仅名称包含 "pool" 的用例

superj test

选项:--filter <substr>(转发给每个套件;仅运行匹配的用例)、--sdk-source <dir>(默认 sdk/sj)、--clang-path <path>

注意事项


Golden-output 测试

用于 SPEC 一致性与代码生成行为,打印输出就是断言。把程序放在 examples/<name>.sj,期望 stdout 放在 examples/expected_<name>.txtsuperj golden examples 编译、运行并做 diff。

// examples/test_my_feature.sj
public class test_my_feature {
    public static void main(String[] args) {
        System.out.println("answer=" + (6 * 7));
    }
}
# examples/expected_test_my_feature.txt
answer=42
superj golden examples   # 自托管;运行所有类别:positive、negative、
                          # smoke、SDK positive/smoke/compile

其他 golden 约定(文件前五行):// ERROR: <substr> 标记一个必须编译失败并带该消息的负面测试;// WARNING: <substr> 标记一个必须警告的编译。不要把单元逻辑断言放进 golden 测试 — 每个新检查都强制重新生成 golden 文件,而第一个不匹配会掩盖其余。改用 sj.test 单元测试。

SuperJ — manual · generated from testing.md at pack time · Powered by superJ — this site is served by superj_web 中文|EN