zoukankan      html  css  js  c++  java
  • 基于pywinauto的Windows平台上自动化测试实践(2)

    一、利用Jython进行Java和Python的数据交互的局限

    在上一节中,利用Jython实现了Java对Python脚本的简单调用,但是jython仅能支持标准的python代码,不支持python扩展包。因而在Java调用的过程中也就堵死了Pywinauto的利用,因此我们需要寻找另一种调用方式。

    二、利用Java.lang中的Runtime类调用Python脚本

    此方法实际上是利用Runtime类新开进程,来独立调用Python脚本。下面是网上找到的例子:

     1 public String python(String pythonPath, String[] params) {
     2         File file = new File(pythonPath);
     3         if (!file.exists()){
     4             return "python脚本不存在!";
     5         }
     6 
     7         String[] command = Arrays.copyOf(new String[]{"python", pythonPath}, params.length + 2);
     8         System.arraycopy(params, 0, command, 2, params.length);
     9 
    10         List<String> res = new ArrayList<>();
    11         try {
    12             Process process = Runtime.getRuntime().exec(command, null, null);
    13             process.waitFor();
    14 
    15             Scanner scanner = new Scanner(process.getInputStream());
    16             while (scanner.hasNextLine()) {
    17                 String line = scanner.nextLine();
    18                 res.add(line);
    19             }
    20 
    21         } catch (IOException e) {
    22             e.printStackTrace();
    23         } catch (InterruptedException e) {
    24             e.printStackTrace();
    25         }
    26 
    27         return "success";
    28     }

    例子中,参数pythonPath就是python脚本的绝对路径,参数params是脚本的参数数组,command就是执行python命令字符串数组,格式就是python + 脚本 + 参数,构造好command后传入exec()中执行新进程,然后调用waitFor()函数等待进程结束,结束后从进程的输入流中获得脚本的输出结果存储到字符串数组中。

    乍一看,上面的代码并没有问题,对于少量的输出结果执行后相当完美,但是当脚本的输出结果大小大于inputStream缓冲区大小时,程序会阻塞在waitFor()函数这里,问题就在于脚本的输出结果是在进程执行完之后才读取,一个好的解决办法就是新开一个清理线程来不断清空缓冲区,也就是输出和读取同时进行,代码如下:

     1 public String python(String pythonPath, String[] params) {
     2     File file = new File(pythonPath);
     3     if (!file.exists()){
     4         return "python脚本不存在!";
     5     }
     6 
     7     String[] command = Arrays.copyOf(new String[]{"python", pythonPath}, params.length + 2);
     8     System.arraycopy(params, 0, command, 2, params.length);
     9 
    10     List<String> res = new ArrayList<>();
    11     try {
    12         Process process = Runtime.getRuntime().exec(command, null, null);
    13         
    14         ClearThread ct = new ClearThread(process);
    15         ct.start();
    16         
    17         process.waitFor();
    18         Thread.sleep(1000);
    19         
    20         ct.setEnd(true);
    21         res = ct.getRes();
    22     } catch (IOException e) {
    23         e.printStackTrace();
    24     } catch (InterruptedException e) {
    25         e.printStackTrace();
    26     }
    27 
    28     return "success";
    29 }
    30 
    31 class ClearThread extends Thread {
    32     Process process;
    33     boolean end;
    34     List<String> res;
    35 
    36     public ClearThread(Process process) {
    37         this.process = process;
    38         end = false;
    39         res = new ArrayList<>();
    40     }
    41 
    42     @Override
    43     public void run() {
    44         if (process == null) {
    45             return;
    46         }
    47         
    48         Scanner scanner = new Scanner(process.getInputStream());
    49         while (process != null && !end) {
    50             while (scanner.hasNextLine()) {
    51                 String line = scanner.nextLine();
    52                 res.add(line);
    53             }
    54         }
    55     }
    56 
    57     public void setEnd(boolean end) {
    58         this.end = end;
    59     }
    60 
    61     public List<String> getRes() {
    62         return res;
    63     }
    64 }
    其中,在脚本执行执行完后调用sleep()让主线程睡眠一秒,否则会导致清理线程可能会还没拿到缓冲区数据就被end标识符结束。

     

    三、最终结果

    下面就是整个case的具体步骤,也就是最终的完整版本,利用Selenium + Robot 实现从web调用本地应用程序,而后利用Pywinauto实现Windows程序的自动化运行,再将结果反馈到Selenium主程序,进行验证或其他操作。

     1 @Test
     2 public void a_deviceUserActivity() {
     3     boolean result = false;
     4     DeviceDetailPage deviceDetailPage = nvBar.openSitesManaged(test).openDevicesDetail("CH-AEM-2012-01");
     5     deviceDetailPage.openRemoteTakeoverPage();
     6     super.sleep(20);
     7     String[] parameter = {};
     8     List<String> returnData = this.python("C:\Selenium\AEMAgentFramework\aem\framework\Pywin.py", parameter);
     9     for(String s : returnData){
    10         System.out.println(s);
    11     }
    12     super.sleep(30);
    13     deviceDetailPage.refreshPage();
    14     if(returnData.size()==3){
    15         result = deviceDetailPage.validateRemoteTakeoverActivity(Constants.getEnvDetails().get("username"), 
    16                 returnData.get(0).substring(3), returnData.get(1).substring(3));
    17     }
    18     if(result)
    19         reportPass("CEN-4732 User Acitvity - Remote Takeover function is working");
    20     else
    21         reportFailure("CEN-4732 User Acitvity - Remote Takeover is failed");
    22 
    23     Assert.assertTrue(result, "CEN-4732 User Acitvity - Remote Takeover is failed");
    24 }
    View Code

    需要注意的是,在调用本地应用程序的过程中网站通常会利用URI Schema这种方式打开本地应用程序,然而Selenium对这种类似Alert的弹框并不支持,因此需要利用Java的Robot工具实现点击操作

    1 Robot robot;
    2 try {
    3     robot = new Robot();
    4     robot.keyPress(java.awt.event.KeyEvent.VK_TAB);
    5     robot.keyPress(java.awt.event.KeyEvent.VK_TAB);
    6     robot.keyPress(java.awt.event.KeyEvent.VK_ENTER);
    7 } catch (AWTException e) {
    8     e.printStackTrace();
    9 }    
  • 相关阅读:
    26 转义符 re模块 方法 random模块 collection模块的Counter方法
    25 正则表达式
    24 from 模块 import 名字
    24 from 模块 import 名字
    24 from 模块 import 名字
    23 析构方法 items系列 hash方法 eq方法
    21 isinstance issubclass 反射 _str_ _new_ _len_ _call_
    20 属性, 类方法, 静态方法. python2与python3的区别.
    python(1)
    python之字符串格式化
  • 原文地址:https://www.cnblogs.com/Seven13G/p/7825957.html
Copyright © 2011-2022 走看看