You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaFX画布全清命令测试:如何验证画布是否为空

解决JavaFX EraseAllCommand的测试难题

1. 绕过GraphicsContext的final类Mock限制

Mockito默认不支持mock final类,只需添加配置启用inline mock maker:

  • 在test/resources目录下创建mockito-extensions/org.mockito.plugins.MockMaker文件,内容写入:mock-maker-inline
  • 之后即可直接mock GraphicsContext,示例测试代码:
@ExtendWith(MockitoExtension.class)
class EraseAllCommandTest {
    @Mock
    private GraphicsContext mockGc;
    private static final double CANVAS_WIDTH = 200.0;
    private static final double CANVAS_HEIGHT = 200.0;

    @Test
    void execute_ShouldCallClearRectWithCorrectParams() {
        EraseAllCommand command = new EraseAllCommand(mockGc, CANVAS_WIDTH, CANVAS_HEIGHT);
        command.execute();

        verify(mockGc).clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
    }
}

2. 解耦测试与实现细节,适配多种方案

如果要避免依赖clearRect这类实现细节,直接验证画布最终状态是更灵活的方式——通过JavaFX的快照功能获取画布像素,判断是否为空:

class EraseAllCommandTest {
    private static final double CANVAS_WIDTH = 200.0;
    private static final double CANVAS_HEIGHT = 200.0;

    @Test
    void execute_ShouldLeaveCanvasEmpty() {
        // 初始化画布并绘制测试内容
        Canvas canvas = new Canvas(CANVAS_WIDTH, CANVAS_HEIGHT);
        GraphicsContext gc = canvas.getGraphicsContext2D();
        gc.setFill(Color.BLUE);
        gc.fillRect(50, 50, 100, 100);

        // 执行全清命令
        EraseAllCommand command = new EraseAllCommand(gc, CANVAS_WIDTH, CANVAS_HEIGHT);
        command.execute();

        // 验证画布为空
        assertTrue(isCanvasEmpty(canvas));
    }

    private boolean isCanvasEmpty(Canvas canvas) {
        WritableImage snapshot = canvas.snapshot(null, null);
        PixelReader pixelReader = snapshot.getPixelReader();
        int width = (int) canvas.getWidth();
        int height = (int) canvas.getHeight();
        int[] pixels = new int[width * height];
        
        // 批量读取像素ARGB值
        pixelReader.getPixels(0, 0, width, height, PixelFormat.getIntArgbInstance(), pixels, 0, width);
        
        // 检查所有像素是否为全透明(ARGB值为0)
        for (int pixel : pixels) {
            if (pixel != 0) {
                return false;
            }
        }
        return true;
    }
}

这种方式下,无论EraseAllCommand是用clearRect、填充背景色还是其他实现,只要最终画布为空,测试就能通过,无需修改测试代码。

3. 优化大画布的测试效率

如果画布尺寸较大,遍历所有像素会影响测试速度,可采用两种优化方式:

  • 抽样检查:每隔N个像素检查一个,平衡准确性与速度
  • 对比空白快照:提前保存空白画布的快照,与全清后的快照对比:
@Test
void execute_ShouldMatchBlankCanvasSnapshot() {
    Canvas canvas = new Canvas(CANVAS_WIDTH, CANVAS_HEIGHT);
    // 保存空白画布快照
    WritableImage blankSnapshot = canvas.snapshot(null, null);

    // 绘制内容后执行全清
    GraphicsContext gc = canvas.getGraphicsContext2D();
    gc.fillOval(50, 50, 100, 100);
    new EraseAllCommand(gc, CANVAS_WIDTH, CANVAS_HEIGHT).execute();

    // 对比快照像素
    WritableImage afterEraseSnapshot = canvas.snapshot(null, null);
    PixelReader blankReader = blankSnapshot.getPixelReader();
    PixelReader afterReader = afterEraseSnapshot.getPixelReader();

    for (int x = 0; x < CANVAS_WIDTH; x += 10) {
        for (int y = 0; y < CANVAS_HEIGHT; y += 10) {
            assertEquals(blankReader.getArgb(x, y), afterReader.getArgb(x, y));
        }
    }
}

内容的提问来源于stack exchange,提问作者TimT

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 19:45:42