测试拖放文件到应用程序

Posted

技术标签:

【中文标题】测试拖放文件到应用程序【英文标题】:Testing drag-and-drop files onto application 【发布时间】:2012-07-31 02:19:50 【问题描述】:

我正在寻找一种方法来从单元测试中将一个文件/多个文件拖放到我的应用程序中。例如,在 Windows 资源管理器中选择一些文件,将它们拖放到我的应用程序中。

我能够测试我的应用程序中两个组件之间的拖放行为(见下文 - 如果您知道更好的方法,请随时指出),但是当数据有来自我的应用程序之外。

当我手动执行拖放操作时,我曾想过使用调试器检查“文件”Transferable,但必须有更好的方法,然后硬编码完整的Transferable

组件之间的拖放测试示例

import org.junit.Test;

import javax.swing.Action;
import javax.swing.JTextField;
import javax.swing.TransferHandler;
import java.awt.event.ActionEvent;

import static org.junit.Assert.assertEquals;

public class DragAndDropTest 
  @Test
  public void dragAndDropBetweenTwoTextFields() 
    JTextField firstField = new JTextField();
    JTextField secondField = new JTextField();
    String testText = "Test text";
    firstField.setText( testText );
    firstField.selectAll();
    Action copyAction = TransferHandler.getCopyAction();
    copyAction.actionPerformed( new ActionEvent( firstField, ActionEvent.ACTION_PERFORMED, "Copy" ) );
    Action pasteAction = TransferHandler.getPasteAction();
    pasteAction.actionPerformed( new ActionEvent( secondField, ActionEvent.ACTION_PERFORMED, "Paste" ) );
    assertEquals( "Text is not copied", testText, secondField.getText() );
  

编辑

基于此问题下的 cmets,我已通过提供硬编码 Transferable 将我的代码 sn-p 更新为“假”拖放。该代码还包含一个小主程序,它只是创建一个可以放置文件的空框架。然后将在控制台上打印路径。

在我的 PC 上,文件的拖放不使用 javaFileListFlavor,而是使用 URI 风格。 以前的经验(请参阅this question)已经告诉我,当从 Java 应用程序外部拖动某些东西时,组件接收到的Transferable 可能会有细微的差别。

所以要完全清楚:我想测试从收到的Transferable 中提取信息的代码部分。 “信息处理”代码(例如,当应用程序接收到文件时会发生什么)可以很容易地进行测试,而无需打扰 D&D。我只需要确保从Transferable 中提取正确的信息,而用硬编码的Transferable 进行测试是愚蠢的。

import org.junit.Test;

import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.TransferHandler;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.IOException;
import java.util.List;

import static org.junit.Assert.assertEquals;

public class DragAndDropTest 
  private static DataFlavor URI_LIST_FLAVOR = null;
  static 
    try 
      URI_LIST_FLAVOR = new DataFlavor( "text/uri-list;class=java.lang.String" );
    
    catch ( ClassNotFoundException ignore ) 
    
  

  @Test
  public void testFileDragAndDrop() throws IOException, UnsupportedFlavorException 
    JComponent testComponent = new JPanel();
    TestingTransferHandler transferHandler = new TestingTransferHandler();
    testComponent.setTransferHandler( transferHandler );
    Clipboard clipBoard = new JLabel(  ).getToolkit().getSystemClipboard();
    Transferable transferable = new Transferable() 
      @Override
      public DataFlavor[] getTransferDataFlavors() 
        return new DataFlavor[]URI_LIST_FLAVOR;
      

      @Override
      public boolean isDataFlavorSupported( DataFlavor flavor ) 
        return flavor == URI_LIST_FLAVOR;
      

      @Override
      public Object getTransferData( DataFlavor flavor ) throws UnsupportedFlavorException, IOException 
        if ( flavor == URI_LIST_FLAVOR ) 
          return new String( "file:///home/robins/Desktop/swingx-1.0-javadoc.jar" );
        
        throw new UnsupportedFlavorException( flavor );
      
    ;
    clipBoard.setContents( transferable, null );
    Action pasteAction = TransferHandler.getPasteAction();
    pasteAction.actionPerformed( new ActionEvent( testComponent, ActionEvent.ACTION_PERFORMED, "Paste" ) );
    assertEquals( transferable.getTransferData( URI_LIST_FLAVOR ), transferHandler.transferable.getTransferData( URI_LIST_FLAVOR ) );
  

  private static class TestingTransferHandler extends TransferHandler
    public Transferable transferable;
    @Override
    public boolean canImport( TransferSupport support ) 
      return true;
    
    @Override
    public boolean importData( TransferSupport support ) 
      transferable = support.getTransferable();
      try
        if ( transferable.isDataFlavorSupported( DataFlavor.javaFileListFlavor ) ) 
          System.out.println("File list flavor");
          List<File> fileList = ( List<File> ) transferable.getTransferData( DataFlavor.javaFileListFlavor );
          System.out.println( "fileList = " + fileList );
        
        if ( transferable.isDataFlavorSupported( URI_LIST_FLAVOR ))
          System.out.println("URI list flavor");
          String uriList = ( String ) transferable.getTransferData( URI_LIST_FLAVOR );
          System.out.println( "uriList = " + uriList );
        
        return true;
       catch ( UnsupportedFlavorException e ) 
        return false;
       catch ( IOException e ) 
        return false;
      
    
  

  public static void main( String[] args ) 
    EventQueue.invokeLater( new Runnable() 
      @Override
      public void run() 
        JFrame frame = new JFrame( "TestFrame" );
        JPanel contentPane = new JPanel( new BorderLayout(  ) );
        contentPane.setTransferHandler( new TestingTransferHandler() );
        frame.setContentPane( contentPane );
        frame.setSize( 200,200 );
        frame.setVisible( true );
        frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
      
     );
  

【问题讨论】:

+1 个棘手的问题 :-) 您可能已经检查过 FEST 是否/如何处理这个问题?没有更多的想法...... 基本上,文件传输是作为ListFiles 提供的。您需要能够使用DataFlavor.javaFileListFlavorDataFlavor 创建Transferable。接下来,您需要了解如何将其注入 DnD API...这就是有趣的地方 @kleopatra 见Fest Wiki。听起来他们只是伪造鼠标事件(这是我在 Swing 组件之间进行 D&D 测试的第一个想法,但对我来说,测试 TransferHandler 就足够了),因此似乎无法从外部拖放文件应用 hmm .. 不太确定我是否正确理解您:假设您想测试您的 TransferHandler 是否可以从任何地方处理 imports,@MadProgrammer 的方法应该会有所帮助。用文件列表填充剪贴板并触发 transferHandler 的粘贴动作进行测试。 @kleopatra 我的意思是没有必要测试完整的 Swing 拖放机制,我只需要确保我的拖放相关代码按预期工作(这下来测试我的TransferHandler 使用与用户使用鼠标执行拖放时相同的输入) 【参考方案1】:

单元测试 Swing GUI 总是很痛苦,更不用说 D&D。不过,我相信这是可以做到的。

有两点需要注意:

    目前,您根本不是在测试 D&D,而是在复制粘贴。这也是一种数据传输的形式,但是copyActionpasteAction的使用导致你真的没有经过任何D&D的步骤

    您提到要检查接收文件的部分,因此您创建了一个自定义 Transferable,但我想说您正在尝试测试错误的东西。处理数据的部分可以实现为处理包含数据的Transferable 的包私有方法,并通过简单的单元测试进行测试(不涉及Swing 组件)

如果您关心不同操作系统之间的 D&D 差异,我相信您应该测试的是 D&D 过程本身是否正常工作,即:

    请求具有数据的组件 (DragSource) 提供数据,并且它提供了数据 请求数据的组件(DropTarget)接收数据并处理它 (可选)您可能希望检查是否允许不同的条件(例如复制与移动等)

您可以使用FESTComponentDragAndDrop 类对此进行测试(请参阅here)。

如果您想编写自己的实现(为什么要这样做?!),您可以: 将源组件和目标组件的TransferHandlers 替换为模拟(或者更准确地说是间谍),在调用真实方法的基础上,您可以验证是否使用预期数据调用了预期方法

【讨论】:

请注意,我没有创建 Transferable。这是关于将文件(本地和网络)拖放到我的应用程序中【参考方案2】:

如果你不局限于单元测试,你可以尝试编写一个 GUI 测试。 Swing 有几个框架,看这个帖子 - Unit testing framework for a Swing UI

几年前我一直在使用jemmy,如果测试很简单,那没关系

【讨论】:

问题是我需要测试从我的应用程序外部拖拽的东西。我查看了 FEST,它仅在同一个 Swing 应用程序中提供拖放支持 啊哈,抱歉,我没听懂。在这种情况下,我的输入毫无意义。顺便说一句挺有意思的,如果你觉得可以的话,请发在这里【参考方案3】:

也许 AutoIt 脚本可以提供帮助:See here

您可以创建一个 Windows 脚本来模拟必要的鼠标或按键事件。然后在你的测试中运行这个脚本,看看会发生什么。

希望这会有所帮助。

【讨论】:

正如问题的 cmets 中所说,我需要测试 Windows/Linux 甚至 Solaris。所以一个 Windows 脚本工具是不够的【参考方案4】:

你见过Robot 类吗?测试人类交互非常酷。我不知道你是否可以拖放文件..但你可以这样做是有道理的!

【讨论】:

【参考方案5】:

您可以使用Swinput 在 Linux 上模拟输入事件。

【讨论】:

【参考方案6】:

尝试使用模拟。我正在使用Mockito 框架。

【讨论】:

模拟如何帮助我测试不同操作系统之间的特定拖放差异?

以上是关于测试拖放文件到应用程序的主要内容,如果未能解决你的问题,请参考以下文章

Xcode UI 测试 - 拖放

我的 Mac 应用程序是不是需要应用文件访问授权密钥来支持拖放?

是否有拖放测试?

在 VB.NET 中拖放并获取文件路径

拖放 - 仅接受文件夹

使用 IStream 拖放虚拟文件