解决web 自动化中上传文件的问题

在做ui自动化测试中,经常会遇到上传文件或者图片的场景,通常的解决方案是自动化工具+autoIT,在这里我介绍一种

通过jdk自带api—— java.awt.Robot 来解决类似问题的方法。java.awt.Robot类主要用于模拟用户点击键盘上的按键,或者模拟用户敲击鼠标等动作。

在做web测试时,弹出窗口如下图所示:


Windows上传文件对话框


对于打开上传文件框是input形式的控件可以用selenium 的方法:driver.findElement(By.id("")).sendKeys("文件路径")来完成上传操作;

如果不是,我们可以利用Robot类来解决该问题。核心思路:

1.打开弹出窗口后,光标在输入框内,然后使用键盘上的keycode写入上传文件具体信息

2.点击Tab键(光标移动到“所有文件”框中)

3.点击Tab键(光标移动到“打开”按钮上)

4.点击Enter键,完成上传文件操作。

注意:该方法不支持中文,因此文件路径和名称不能包括中文。

点击键盘按键核心代码如下:

robot.keyPress(keyCodes);

robot.keyRelease(keyCodes);

点击Tab键

robot.keyPress(KeyEvent.VK_TAB);

robot.keyRelease(KeyEvent.VK_TAB);

点击Enter键

robot.keyPress(KeyEvent.VK_ENTER);

robot.keyRelease(KeyEvent.VK_ENTER);

输入字符‘a’

robot.keyPress(KeyEvent. VK_A);

robot.keyRelease(KeyEvent. VK_A);

输入字符‘A’,需要Shift键的配合

robot.keyPress(KeyEvent.VK_SHIFT);

robot.keyPress(KeyEvent.VK_A);

robot.keyRelease(KeyEvent.VK_A);

robot.keyRelease(KeyEvent.VK_SHIFT);

更多的按键信息请参考:

https://docs.oracle.com/javase/8/docs/api/java/awt/event/KeyEvent.html

由于每次输入字符都需要调用robot.keyPress和robot.keyRelease方法,当处多字符写入的场景时效率太低,所以我们需要编写方便的API便于调用,核心代码如下:

import java.awt.AWTException;

import java.awt.Robot;

import java.awt.event.KeyEvent;

import static java.awt.event.KeyEvent.*;

public class RobotKeyboard {

   private static RobotKeyboard uniqueInstance = null;

    private Robot robot;

   publicRobotKeyboard()throws AWTException {

        this.robot = new Robot();

   }


   public static synchronized  RobotKeyboardgetInstance()throws AWTException {

        if (uniqueInstance == null) {

            uniqueInstance = new RobotKeyboard();

        }

        return uniqueInstance;

    }

   //输入字符串

   public void typeWords(CharSequence characters) {


        int length = characters.length();

        for (int i = 0; i < length; i++) {

            char character = characters.charAt(i);

            typeChar(character);

        }

   }

 //输入特殊键盘按键

   public void typeKey(String p_string,int p_times) {


       if (p_string.equalsIgnoreCase("Tab"))

       doTypeLoop(KeyEvent.VK_TAB,p_times);

       else if (p_string.equalsIgnoreCase("Enter"))

       doTypeLoop(KeyEvent.VK_ENTER,p_times);

       else if (p_string.equalsIgnoreCase("Up"))

       doTypeLoop(KeyEvent.VK_UP,p_times);

       else if (p_string.equalsIgnoreCase("Down"))

       doTypeLoop(KeyEvent.VK_DOWN,p_times);

       else if (p_string.equalsIgnoreCase("Left"))

       doTypeLoop(KeyEvent.VK_LEFT,p_times);

       else if (p_string.equalsIgnoreCase("Right"))

       doTypeLoop(KeyEvent.VK_RIGHT,p_times);

       else if (p_string.equalsIgnoreCase("Shift"))

       doTypeLoop(KeyEvent.VK_SHIFT,p_times);

       else if (p_string.equalsIgnoreCase("ESC"))

       doTypeLoop(KeyEvent.VK_ESCAPE,p_times);

       else if (p_string.equalsIgnoreCase("Backspace"))

       doTypeLoop(KeyEvent.VK_BACK_SPACE,p_times);

       else doTypeLoop(0,p_times);

   }


   //输入常用单个字符

   public void typeChar(char character) {

        switch (character) {

        case 'a': doType(VK_A); break;

        case 'b': doType(VK_B); break;

        case 'c': doType(VK_C); break;

        case 'd': doType(VK_D); break;

        case 'e': doType(VK_E); break;

        case 'f': doType(VK_F); break;

        case 'g': doType(VK_G); break;

        case 'h': doType(VK_H); break;

        case 'i': doType(VK_I); break;

        case 'j': doType(VK_J); break;

        case 'k': doType(VK_K); break;

        case 'l': doType(VK_L); break;

        case 'm': doType(VK_M); break;

        case 'n': doType(VK_N); break;

        case 'o': doType(VK_O); break;

        case 'p': doType(VK_P); break;

        case 'q': doType(VK_Q); break;

        case 'r': doType(VK_R); break;

        case 's': doType(VK_S); break;

        case 't': doType(VK_T); break;

        case 'u': doType(VK_U); break;

        case 'v': doType(VK_V); break;

        case 'w': doType(VK_W); break;

        case 'x': doType(VK_X); break;

        case 'y': doType(VK_Y); break;

        case 'z': doType(VK_Z); break;

        case 'A': doType(VK_SHIFT, VK_A); break;

        case 'B': doType(VK_SHIFT, VK_B); break;

        case 'C': doType(VK_SHIFT, VK_C); break;

        case 'D': doType(VK_SHIFT, VK_D); break;

        case 'E': doType(VK_SHIFT, VK_E); break;

        case 'F': doType(VK_SHIFT, VK_F); break;

        case 'G': doType(VK_SHIFT, VK_G); break;

        case 'H': doType(VK_SHIFT, VK_H); break;

        case 'I': doType(VK_SHIFT, VK_I); break;

        case 'J': doType(VK_SHIFT, VK_J); break;

        case 'K': doType(VK_SHIFT, VK_K); break;

        case 'L': doType(VK_SHIFT, VK_L); break;

        case 'M': doType(VK_SHIFT, VK_M); break;

        case 'N': doType(VK_SHIFT, VK_N); break;

        case 'O': doType(VK_SHIFT, VK_O); break;

        case 'P': doType(VK_SHIFT, VK_P); break;

        case 'Q': doType(VK_SHIFT, VK_Q); break;

        case 'R': doType(VK_SHIFT, VK_R); break;

        case 'S': doType(VK_SHIFT, VK_S); break;

        case 'T': doType(VK_SHIFT, VK_T); break;

        case 'U': doType(VK_SHIFT, VK_U); break;

        case 'V': doType(VK_SHIFT, VK_V); break;

        case 'W': doType(VK_SHIFT, VK_W); break;

        case 'X': doType(VK_SHIFT, VK_X); break;

        case 'Y': doType(VK_SHIFT, VK_Y); break;

        case 'Z': doType(VK_SHIFT, VK_Z); break;

        case '`': doType(VK_BACK_QUOTE); break;

        case '0': doType(VK_0); break;

        case '1': doType(VK_1); break;

        case '2': doType(VK_2); break;

        case '3': doType(VK_3); break;

        case '4': doType(VK_4); break;

        case '5': doType(VK_5); break;

        case '6': doType(VK_6); break;

        case '7': doType(VK_7); break;

        case '8': doType(VK_8); break;

        case '9': doType(VK_9); break;

        case '-': doType(VK_MINUS); break;

        case '=': doType(VK_EQUALS); break;

        case '~': doType(VK_SHIFT, VK_BACK_QUOTE); break;

        case '!': doType(VK_EXCLAMATION_MARK); break;

        case '@': doType(VK_AT); break;

        case '#': doType(VK_NUMBER_SIGN); break;

        case '$': doType(VK_DOLLAR); break;

        case '%': doType(VK_SHIFT, VK_5); break;

        case '^': doType(VK_CIRCUMFLEX); break;

        case '&': doType(VK_AMPERSAND); break;

        case '*': doType(VK_ASTERISK); break;

        case '(': doType(VK_LEFT_PARENTHESIS); break;

        case ')': doType(VK_RIGHT_PARENTHESIS); break;

        case '_': doType(VK_UNDERSCORE); break;

        case '+': doType(VK_PLUS); break;

        case '\t': doType(VK_TAB); break;

        case '\n': doType(VK_ENTER); break;

        case '[': doType(VK_OPEN_BRACKET); break;

        case ']': doType(VK_CLOSE_BRACKET); break;

        case '\\': doType(VK_BACK_SLASH); break;

        case '{': doType(VK_SHIFT, VK_OPEN_BRACKET); break;

        case '}': doType(VK_SHIFT, VK_CLOSE_BRACKET); break;

        case '|': doType(VK_SHIFT, VK_BACK_SLASH); break;

        case ';': doType(VK_SEMICOLON); break;

        case ':': doType(VK_SHIFT, VK_SEMICOLON); break;

        case '\'': doType(VK_QUOTE); break;

        case '"': doType(VK_QUOTEDBL); break;

        case ',': doType(VK_COMMA); break;

        case '<': doType(VK_LESS); break;

        case '.': doType(VK_PERIOD); break;

        case '>': doType(VK_GREATER); break;

        case '/': doType(VK_SLASH); break;

        case '?': doType(VK_SHIFT, VK_SLASH); break;

        case ' ': doType(VK_SPACE); break;

        default:

            throw new IllegalArgumentException("Cannot type character " + character);

        }

   }


   //无需shift键配合的单字符输入的核心API

   private void doType(int keyCodes) {

    if(keyCodes==0)

    {

        return;

    }

    robot.keyPress(keyCodes);

    robot.keyRelease(keyCodes);

 }


   //循环输入键值

   private void doTypeLoop(int keyCodes,int times){

    if(keyCodes==0)

    {

        return;

    }

    for(int i=0;i<times;i++){

        robot.keyPress(keyCodes);

         robot.keyRelease(keyCodes);

    }


 }

   //需要shift键配合的单字符输入的核心API

   private void doType(int keyShit,int keyCodes) {

    if(keyCodes==0)

    {

        return;

    }

    robot.keyPress(keyShit);

    robot.keyPress(keyCodes);

    robot.keyRelease(keyCodes);

    robot.keyRelease(keyShit);

    }

}


使用代码如下:

public static void main(String[] args) throws AWTException {

    RobotKeyboard.getInstance().type("D:\\test\\test.png"); //输入要上传的文件

    RobotKeyboard.getInstance().typeKey("Tab", 2); //点击两次Tab键

    RobotKeyboard.getInstance().typeKey("Enter", 1);//点击一次Tab键


}

这里只提供了基础代码,大家可以根据项目实际需求进行改写!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352