You need to enable JavaScript to run this app. 如何为自定义SWT ColumnRatioLayout编写JUnit占比验证测试
优惠活动
大模型
产品
解决方案
定价
更多

如何为自定义SWT ColumnRatioLayout编写JUnit占比验证测试

问题修复与实现方案

一、现有问题排查

1. 自定义布局本身的bug

原ColumnRatioLayout里的calculatePercentAndConsumedPercent方法用了Java基本类型作为入参,基本类型是值传递,方法内部修改的参数不会同步到外部调用处,导致computeSize方法中的percent永远是0,计算逻辑完全失效。

2. 测试代码的问题

  • 调用_comp.computeSize时还没有添加子控件,空容器的计算结果自然是0
  • 子控件是无内容的空Composite,默认首选尺寸为0,没有参考意义
  • 手动给子控件调用setSize会被布局管理器的自动计算覆盖,属于无效操作
  • 没有手动触发布局重算,SWT布局不会自动立刻生效

二、修复后的实现代码

1. 修复ColumnRatioLayout

public class ColumnRatioLayout extends Layout {
    int[] percentages;
    public ColumnRatioLayout(int... percentages) {
        this.percentages = percentages;
    }

    @Override
    protected Point computeSize(Composite composite, int wHint, int hHint, boolean flushCache) {
        Control[] children = composite.getChildren();
        int height = hHint;
        int width = wHint;
        int consumedPercent = 0;
        for (int i = 0; i < children.length; i++) {
            int percent;
            // 直接内联逻辑,避免值传递问题
            if (i >= percentages.length) {
                percent = (100 - consumedPercent) / (children.length - percentages.length);
            } else {
                percent = percentages[i];
                consumedPercent += percent;
            }
            Point childSize = children[i].computeSize(wHint == -1 ? -1 : wHint * percent / 100, hHint);
            if (wHint == SWT.DEFAULT) {
                width = Math.max(width, childSize.x * 100 / percent);
            }
            if (hHint == SWT.DEFAULT) {
                height = Math.max(height, childSize.y);
            }
        }
        return new Point(Math.max(width, 0), Math.max(height, 0));
    }

    @Override
    protected void layout(Composite composite, boolean flushCache) {
        Control[] children = composite.getChildren();
        Rectangle available = composite.getClientArea();
        int x = available.x;
        int consumedPercent = 0;
        for (int i = 0; i < children.length - 1; i++) {
            int percent;
            if (i >= percentages.length) {
                percent = (100 - consumedPercent) / (children.length - percentages.length);
            } else {
                percent = percentages[i];
                consumedPercent += percent;
            }
            int w = available.width * percent / 100;
            children[i].setBounds(x, available.y, w, available.height);
            x += w;
        }
        if (children.length > 0) {
            children[children.length - 1].setBounds(x, available.y,
                    available.width - (x - available.x), available.height);
        }
    }
}

2. 正确的JUnit测试代码

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class ColumnRatioLayoutTest {

    private static Display _display;
    private static Shell _shell;
    private static Composite _comp;

    @BeforeAll
    public static void setUpAll() {
        _display = new Display();
        _shell = new Shell(_display);
        _comp = new Composite(_shell, SWT.NONE);
        // 给父容器设置固定宽度1000px,方便按比例计算验证
        _comp.setSize(1000, 200);
    }

    @Test
    public void setLayoutTest() {
        // 先添加子控件
        Composite comp1 = new Composite(_comp, SWT.NONE);
        comp1.setLayout(new FillLayout());
        Composite comp2 = new Composite(_comp, SWT.NONE);
        comp2.setLayout(new FillLayout());

        // 设置布局后触发重算
        int[] colRatio = {20, 80};
        ColumnRatioLayout colLayout = new ColumnRatioLayout(colRatio);
        _comp.setLayout(colLayout);
        _comp.layout(); // 手动触发布局计算

        // 获取子控件尺寸验证比例
        Point size1 = comp1.getSize();
        Point size2 = comp2.getSize();

        System.out.println("Comp1宽度:" + size1.x);
        System.out.println("Comp2宽度:" + size2.x);

        // 1000px的20%是200,80%是800,允许1px的整数计算误差
        assertEquals(200, size1.x, 1);
        assertEquals(800, size2.x, 1);
        // 验证宽度是4倍关系
        assertEquals(4, size2.x / (double)size1.x, 0.1);
    }
}

三、验证逻辑说明

测试用例给父容器设置了固定宽度1000px,按照20:80的比例,子控件宽度应该分别为200px和800px,刚好满足4倍的比例关系,通过JUnit断言直接验证结果即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.16 11:15:01