如何在无头环境中测试 Swing GUI?

问题描述 投票:0回答:1

假设我想测试这个简单的

JButton
扩展

package app;

import solution.common.utils.MathConverter;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class JDropdownButton
        extends JButton
        implements ActionListener {
    private JPopupMenu popupMenu;

    public JDropdownButton() {
        this(null, null);
    }

    public JDropdownButton(String text, Icon icon) {
        super(text, icon);
        super.addActionListener(this);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (null == popupMenu || null == popupMenu.getSubElements()) {
            return;
        }

        if (!popupMenu.isVisible()) {
            Point p = getLocationOnScreen();
            popupMenu.setLocation(MathConverter.doubleToInt(p.getX()),
                    MathConverter.doubleToInt(p.getY()) + getHeight());
            popupMenu.setVisible(true);
        }
    }

    public void setDropdownMenu(JPopupMenu menu) {
        popupMenu = menu;
        if (popupMenu != null) {
            popupMenu.setInvoker(this);
        }
    }
}

此时,我只对测试单击按钮是否显示弹出窗口感兴趣。如果我运行这个

package app;

import org.junit.jupiter.api.Test;

import javax.swing.*;
import java.awt.event.ActionEvent;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

class JDropdownButtonTest {
    @Test
    void actionPerformed_showsPopup() {
        JDropdownButton dropdownButton = new JDropdownButton();
        JPopupMenu popupMenu = new JPopupMenu();
        dropdownButton.setDropdownMenu(popupMenu);
//        JFrame frame = new JFrame();
//        frame.add(dropdownButton);
//        frame.setVisible(true);
        assertFalse(popupMenu.isVisible());
        dropdownButton.doClick();
        assertTrue(popupMenu.isVisible());
    }
}

我明白了

java.awt.IllegalComponentStateException: component must be showing on the screen to determine its location

    at java.awt.Component.getLocationOnScreen_NoTreeLock(Component.java:2062)
    at java.awt.Component.getLocationOnScreen(Component.java:2036)
    at app.JDropdownButton.actionPerformed(JDropdownButton.java:50)

所以它必须要显示。由于 Mockito 无法区分真正的调用和设置调用,因此这将抛出相同的异常

    @Test
    void actionPerformed_showsPopup() {
        JDropdownButton dropdownButton = spy(JDropdownButton.class);
        given(dropdownButton.getLocationOnScreen()).willReturn(new Point(0,0));
        JPopupMenu popupMenu = new JPopupMenu();
        dropdownButton.setDropdownMenu(popupMenu);
//        JFrame frame = new JFrame();
//        frame.add(dropdownButton);
//        frame.setVisible(true);
        assertFalse(popupMenu.isVisible());
        dropdownButton.doClick();
        assertTrue(popupMenu.isVisible());
    }

我可以取消注释这些行,测试运行良好,但是 TeamCity 服务器上的 CI 构建将失败,并出现“无头异常”,因为没有可用的图形环境

所以我需要一个强大的 GUI 测试,也可以在无头环境中运行

我该怎么做? 更新 CI 服务器的 Docker 镜像是唯一的解决方案吗?

java swing user-interface testing
1个回答
0
投票

这并不是真正的答案,更像是一种解决方法。

doReturn()
结构避免了实际的方法调用(我猜是因为
when()
返回一个“吞噬”后续调用的模拟)

    @Test
    void actionPerformed_showsPopup() {
        JDropdownButton dropdownButton = spy(JDropdownButton.class);
        doReturn(new Point(0,0)).when(dropdownButton).getLocationOnScreen();
        JPopupMenu popupMenu = new JPopupMenu();
        dropdownButton.setDropdownMenu(popupMenu);
        assertFalse(popupMenu.isVisible());
        dropdownButton.doClick();
        assertTrue(popupMenu.isVisible());
    }
© www.soinside.com 2019 - 2024. All rights reserved.