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
相关产品推荐
相关产品推荐

