在做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 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键 } 这里只提供了基础代码,大家可以根据项目实际需求进行改写!