Appium 启发之作 - 让基于 webdriver 的日常调试方便些

suky2000 · 发布于 2017年07月22日 · 最后由 thanksdanny 回复于 2017年08月18日 · 1420 次阅读
本帖已被设为精华帖!

写在前面

从最初开始接触接触webdriver的自动化测试工具一来就一直有个小困扰, 那就是调试的时候不是很方便. 其实我们在编写脚本的时候除了设计阶段, 一定的时间是在调试测试步骤和element上. 但是常规的写法在调试的时候每次总是要重启webdriver包括seleium和appium, 不是很方便. 其实这个功能在一些收费的工具上是作为基本步骤的, 比如UFT或者RFT等功能自动化工具. 前几天在论坛上看到一位同行写出了一个方式去实现在不重启webdriver的情况下能够方便的调试一些操作基于androiddriver的, 受到启发. 看孩子和热蒙了之余做了些改动和加了点自己的想法, 写了一个很小的工具, 希望能给测试的同行们提供一点方便.

参考帖子: https://testerhome.com/topics/9040(使用 java 动态加载机制模拟脚本语言的效果)

重点在这

看似理想点的操作方式是这样的, 你想操作webdriver, 比如selenium的chrome driver :

  • 启动一个chromedriver, 可以是空白的, 或者是已经打开一个网址的(http://www.baidu.com).
  • 写个操作, 比如往搜索框里面输入testerhome关键字.
driver.findElementById("kw").sendKeys("Testerhome");
  • 你执行一下,没啥问题. 然后就想在加一个 click旁边搜索按钮一下.
driver.findElementById("su").click();
  • 但是问题来了, 你需要修改代码在跑一次,才能实现这两步操作.这就是问题所在.

其实我们在常规的操作中只是想简单点, 比如:

  • 启动一个chromedriver, 可以是空白的, 或者是已经打开一个网址的(http://www.baidu.com).
  • 写个操作, 比如往搜索框里面输入testerhome关键字.
  • 执行一下,没啥问题. 然后修改脚本添加代码click旁边搜索按钮一下.
  • 在整个修改和执行期间, 后面开启的浏览器, 一直在哪里, 它会伴随的你不断修改的代码,几乎时时执行,无需重启浏览器.你甚至可以随时注释掉一句代码, 在跑一次而无需重启webdriver.

给个小结论

我们需要的只是让最开始启动的webdriver的session, 比如浏览器的一直在哪里而不重置或者丢失, 就可以了. 基于此, 就可以随意的执行你的自动化代码, 看起来像动态的方式一样, 所以最开始提到的帖子里面, 同行用的是java的reflect, 随时编译执行而无须重启. 我最早接触这种操作是开始于我做的一个操作数据库的轻量IDE, 启动和load一些驱动和主程序用到反射这个概念, 但是并没有深入的研究它. 这次正好看到这位同行分享的方法, 受到启发, 就简单的扩展了一下.

关于这个不是工具的工具

  • 这个小工具叫MteSenseWdd, 就是一个jar文件,MteSense-Wdd-beta-0.1.1.jar.
  • 你可以把这个jar放到任何你需要的自动化的classpath里面,前提是基于webdriver的测试.
  • 没有java ide的限制, eclipse, idea都可以.
  • 适用于webdriver的自动化调试, 比如 chrome, firefox, safari, iosdriver, androidsriver等.
  • 工具仅供调试只用, 不能替代你真正的业务自动化脚本, 仅是为你调试提供一些方便.
  • 想正确的调用需要你的classpath里面要有 selenium standalone, 和 appium java clent的相关jar文件.
  • 操作方式极其简单, 真的.

举个栗子

工具的使用需要你建立两个java 文件, 一个用来启动webdriver(没它啥都做不了)和调用MteSenseLoader(这个是主要的方法), 一个是用来写你调试代码的java文件, 之所以要用JAVA文件是为了方便你使用 java ide那些绚丽的功能, 什么敲点出方法之类的, 方便你操作的.最终你的所有调试webdriver的代码都只能写到第二java文件的指定方法里.

第一个java文件例子(MteSenseWdadTest)

package com.mte.wdd.test;

import com.mte.wdd.main.MteSenseLoader;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.remote.CapabilityType;
import org.openqa.selenium.remote.DesiredCapabilities;

import java.util.concurrent.TimeUnit;

/**
 * Created by java on 20/07/2017.
 */
public class MteSenseWdadTest {

    ChromeDriver driver;

    @Before
    public void setUp() throws Exception {
        System.setProperty("webdriver.chrome.driver", "./config/chromedriver");
        DesiredCapabilities capabilities = DesiredCapabilities.chrome();
        capabilities.setCapability(CapabilityType.ACCEPT_SSL_CERTS, true);
        driver = new ChromeDriver(capabilities);

        driver.manage().timeouts()
                .pageLoadTimeout(20, TimeUnit.SECONDS);

        driver.manage().timeouts()
                .implicitlyWait(10, TimeUnit.SECONDS);

        driver.manage().timeouts()
                .setScriptTimeout(10, TimeUnit.SECONDS);
        driver.manage().window().maximize();
    }

    @Test
    public void testMain() throws Exception {

        MteSenseLoader loader = new MteSenseLoader();

        loader.senseLoader("chrome","./src/MteSenseInstanceUpdate.java", "MteSenseInstanceUpdate", "http://www.baidu.com", "runDynamicAction", driver);

    }

    @After
    public void tearDown() throws Exception {
        driver.quit();
    }

}

第二个java文件例子(MteSenseInstanceUpdate), 你所有的调试代码都要写到这个文件的runDynamicAction() 方法里面去.


import org.openqa.selenium.chrome.ChromeDriver;

/**
 * Created by java on 20/07/2017.
 */
public class MteSenseInstanceUpdate {

    public static void runDynamicAction(ChromeDriver driver) {

        driver.findElementById("kw").sendKeys("Testerhome");
        driver.findElementById("su").click();
//        driver.get("http://wwww.baidu.com");

    }

}

必须解释一下

请注意下面的代码

@Test
public void testMain() throws Exception {

    MteSenseLoader loader = new MteSenseLoader();

    loader.senseLoader("chrome","./src/MteSenseInstanceUpdate.java", "MteSenseInstanceUpdate", "http://www.baidu.com", "runDynamicAction", driver);

}

senseLoader 方法有六个参数

  • drivertype : 支持这六个关键字 chrome, firefox, safari, ios, android.
  • 用来调试的java文件的路径.
  • 用来调试的java文件的类名, 如果你没有放在package下那就直接些class名字, 如果有package的名字, 就需要些完整比如 com.xxx.xxx.MteSenseInstanceUpdate之类的.
  • 需要预先打开的网址, 调试浏览器之类的需要, 不需要可以吧这个字段传入 null.
  • 用来调试的java文件的方法名字.
  • 你在第一个java文件中创建的webdriver的实例.这个参数我定义的类型是RemoteWebDriver.

开始折腾把

按照栗子的步骤

  • 执行MteSenseWdadTest, run as junit.
  • 开始修改MteSenseInstanceUpdate的runDynamicAction方法的webdriver的代码.
  • 完了.

无图无真相

来点注意事项

  • 你需要确认你的一个java文件能正常的启动wendriver, 有不能启动的情况的可以去搜索, 这不是废话嘛.
  • 你只需要修改runDynamicAction这个方法里面的代码, 不要停止MteSenseWdadTest的运行.
  • 每次当你修改了runDynamicAction里面的调试代码并且save了, 你的操作代码就会自动执行, 所以如果你不确定就别save.
  • 如果你使用idea作为java ide, 请把"Use "Safe Write"" 选项取消掉, 在Preferences-->Appearance&Behavior-->System Settings. 不取消会造成 一次修改 两次保存, 也就是你修改的调试代码会执行两次.
  • runDynamicAction方法webdriver参数必须要和你在一个java文件定义的一样.
  • Junit不是唯一的方式, 其实你怎么写都没关, 只要正确启动个webdriver 和MteSenseLoader就行.
  • 这个小工具只是给大家提供点方便, 不能替代你常规的自动化业务脚本.
  • 后续有了再说.

最后陈述

  • 这个小工具只是Beta的Beta版, 我仅在 macOS下测试了 chrome和iosdrver, 其他type如果出现问题请告诉我.
  • 你能够得到这个jar和一些帮助在 这里(https://github.com/PandaSense/MteSenseWdd).
  • 只实现基本功能, 代码需要修改的, 操作基本不变,暂时先不开放, 但是你基本可以在我开始提到的帖子里面了解到.
  • 问题会有的, 大家轻喷.

最后的最后

如果觉得还对付用, 或者 能给你带来点方便, 请在 github的项目上 点下star, 非常感谢.

如果有更好的建议和要求, 可以讨论是否添加, 想法还是有的....

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 19 条回复
104 seveniruby 将本帖设为了精华贴 07月23日 01:50
10075

😀 不错,明天试试

F58ce0

以后调试就方便了

5467

有点复杂,介绍下我们之前用appium调试的简单思路:

因为appium是C/S架构,每次测试执行的上下文信息都保存在appium server端,其中最主要的就是会话session,所以,只要重写或者添加个driver初始化的方法,先去server端获取下已存在的session信息,就能实现无需重启的单步调试了

854b0b

appium有个超时设置,是无操作一段时间会自动关闭session,请问这个时间是在那里设置的?调试的时候有时会比较慢或者什么之类的就容易超时了

2775
5467xubin98246 回复

我的方式只是保证在一个session期间的调试, 你的这种方式我没有试过,能分享下具体的方式吗?

2775
854b0bhellomm 回复

http://www.cnblogs.com/xmlbw/p/4510153.html 我搜到的, 你看下 里面的newCommandTimeout

5467
2775suky2000 回复

pythonappium客户端为例:

webdriver初始化的地方添加reconnect参数

如果reconnecttrue的情况下,直接获取server端的session信息,并直接将这些信息保存至客户端脚本上下文中

调试时,脚本代码中只要将reconnect值设为true就行了

2775
5467xubin98246 回复

看代码, 这操作应该是在创建webdriver之前操作的, 得到已经存在的session,来build webdrive.这个sessionResponse 和 execute(Command.GET_ALL_SESSIONS),是项目自己定义的吗?还是appium 自带的api?

Db42eb
2775suky2000 回复

估计是封装的东西

2775
Db42ebmads 回复

嗯, 能有不同的方式实现 挺好的, 至少多个思路. 也许以后哪里就用上了

5467
2775suky2000 回复

appium客户端中webdriver管理的部分实际上就是selenium,上面这个命令也是selenium中默认就有的参考

854b0b hellomm 我的 selenium日常调试 中提及了此贴 07月24日 14:07
2775
5467xubin98246 回复

不错, 晚上回去看看, 感谢分享

12481

补充,在网页端的方法:
1.命令行启动:F:>java -jar selenium-server-standalone-2.42.2.jar

  1. 修改以下方法:
def __init__(self, command_executor='http://127.0.0.1:4444/wd/hub', desired_capabilities=None, browser_profile=None, proxy=None, keep_alive=False, file_detector=None,reconnect = False):

        if reconnect:
            sessionResponse = self.execute(Command.GET_ALL_SESSIONS)
            print sessionResponse
            if sessionResponse.has_key('sessionId') and sessionResponse['sessionId']!=None:
                self.session_id = sessionResponse['sessionId']
                self.capabilities =sessionResponse['value']
            else:
                if len(sessionResponse['value']) > 0:
                    print sessionResponse['value'][0]['id']
                    self.session_id=sessionResponse['value'][0]['id']
                    self.capabilities = sessionResponse['value']
        else:
            self.start_session(desired_capabilities, browser_profile)

3. 执行端代码

PROXY = "localhost:4444"
   # Create a copy of desired capabilities object.
   desired_capabilities = driver.DesiredCapabilities.INTERNETEXPLORER.copy()
   # Change the proxy properties of that copy.
   desired_capabilities['proxy'] = {
       "httpProxy": PROXY,
       "ftpProxy": PROXY,
       "sslProxy": PROXY,
       "noProxy": None,
       "proxyType": "MANUAL",
       "class": "org.openqa.selenium.Proxy",
       "autodetect": False
   }

   # you have to use remote, otherwise you'll have to code it yourself in python to
   # dynamically changing the system proxy preferences
   start_driver = driver.Remote("http://localhost:4444/wd/hub", desired_capabilities,reconnect=True)
2562

哇噢,好厉害

C31573
2562carl 回复

你好 我还是碰到了无法使用KEYEVENT的问题 使用那3种方法都没有解决 可以回复一下我的帖子吗?非常感谢

16280

跟我这个配合在一起就好了:
https://github.com/fudax/selenium_recorder

405062

python交互模式非常适合做测试代码调试,appium修改个参数保持会话长时间连接就行,网页目前长时间保持会话不断的叁数未找到。参考:基于 webdriver 的日常调试方便些 python 篇。

9f1b82
405062sunny_2016 回复

同意,我是习惯先写个简单py文件,用ipython执行该py,然后就可以愉快的在ipython中做调试了

3165

马克一下!

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册