Appium 【问题解决】用例执行过程中 app 界面发生切换,desired_caps 中 activity 该如何设置才能满足用例执行过程中 app 在不同界面所需要的、匹配的 activity?

strayeagle · 2014年10月08日 · 最后由 sukekes 回复于 2015年11月19日 · 132 次阅读

测试环境:
安卓,python+appium

问题描述如下:
我的 py 文件中目前有 5 个测试用例,功能分别如下:
用例 1、完成卸载 app 操作;
用例 2、完成 app 的安装操作;
用例 3、在用例 2 的基础上,app 启动后界面是登录界面,判断这个登录界面上是否存在一个 powerer-by 信息;
用例 4、是个登录操作,在登录界面上输入 username/password 进行登录操作;
用例 5、在用例 4 的基础上,登录进去后,判断 app 的侧边栏是否有 powered-by 信息

用例 1、用例 2,activity 使用的是 com.xxx.ui.FlowPager
用例 3、用例 4,activity 使用的是 com.xxx.ui.LoginPager
用例 5,activity 使用的是 com.xxx.ui.MainPager

这 5 个用例,使用 3 个不同的 activity,而在函数 get_desired_capabilities 中初始化的 appActivity 是 com.xxx.ui.FlowPager;
也就是说,我在 desired_caps 中设置了 activity,一些用例执行通过了,执行其他用例的时候,需要别的 activity 了,也就是前 2 个用例执行可成功;后面的用例执行就失败了。
如果我把 get_desired_capabilities 函数中 appActivity 修改为用例 3~4 需要的 activity,保留用例 3 和 4,其他用例注释掉,则用例 3 和 4 执行是 OK 的。

用例 setup 和 teardown 代码如下;

def setUp(self):
    # 启动所有的测试桩
    StubFactory().start()

    #初始化driver
    self.driver = getDriverInfo().androidDriverInfo()

    logging.info("\n============= Begin to test [ " + self.getDoc() + " ] ===============\n")

def tearDown(self):
    # 停止所有的测试桩
    StubFactory().stop()

    self.driver.quit()

    logging.info("\n============= End to test [ " + self.getDoc() + " ] ===============\n")

driver 信息的获取,使用另外一个类,代码片段如下:

def get_desired_capabilities(app):
    desired_caps = {
        'platformName': 'Android',
        'platformVersion': '4.3',
        'deviceName': 'Android Emulator',
        'appPackage' : 'com.xxx.phone',
        'appActivity' : 'com.xxx.ui.FlowPager',
        'app': PATH(r'../testApp/' + app)
    }
,
    return desired_caps

测试用例 3 的代码如下:


def testOutPowerby(self):
    ''' 安卓 --> 登录界面上是否有powerBy测试  '''
    driver = self.driver

    #点击掉拒绝,以展示UI中的resource-id
    try:
        title = driver.find_element_by_id("com.xxx.phone:id/alert_btn_2x")
        title.click()
    except  NoSuchElementException as e:
        print e.message

    #校验app的登录界面上是否有powered-by信息
    logging.info(' 开始检测app的登录界面上是否有powered-by信息 ... \n')
    expect = True
    result = driver.find_element_by_id('com.xxx.phone:id/powered_by').is_displayed()
    self.assertEqual(expect, result, '\n app的登录界面上不存在powered-by信息! \n')

该用例执行报错:

WebDriverException: Message: u'A new session could not be created. (Original error: com.xxx.phone/com.xxx.ui.FlowPager never started. Current: com.xxx.phone/com.xxx.ui.LoginPager)' 

日志里报错,是说 com.xxx.ui.FlowPager 没启动,而当前启动的则是 com.xxx.ui.LoginPager,是要每次根据用例,去合理的修改 appActivity 的值吗?该怎么修改才能确保用例能够在不同界面间连贯去执行呢?

请问大家在实际使用中遇到这个情况是如何解决的呢?

共收到 15 条回复 时间 点赞

这里也看不懂。

虽然看不太明白,貌似是用例互相依赖了吧?
如果第二个用例必须登录后才能进行,那操作应该从 MainPager 开始操作,或者 driver.start_activity
一般一个用例结束后 driver.quit,第二个用例用新的 driver,这样可以清理环境。

#2 楼 @sanlengjingvv 请问 driver 不是只要初始化一次嘛?设置一个全局的 driver,所有用例都使用这个 driver 属性信息

#2 楼 @sanlengjingvv 的意思看看你的 setUp 和 tearDown

#2 楼 @sanlengjingvv
我的测试基类代码如下:(TestCaseBase.py)

#!/usr/bin/env python
#-*- coding:UTF-8 -*-

import logging
import unittest
from common.stub.StubFactory import StubFactory

import os
from appium import webdriver
from common.testCaseBase.getDriver import *


class TestCaseBase(unittest.TestCase):

    def getDoc(self):
        '''获取用例 __doc__信息'''
        doc = super(TestCaseBase,self).shortDescription()
        return doc    

    def setUp(self):
        # 启动所有的测试桩,主要是配置文件的解析、路径解析等
        StubFactory().start()

        #初始化driver
        self.driver = getDriverInfo().androidDriverInfo()

        logging.info("\n============= Begin to test [ " + self.getDoc() + " ] ===============\n")

    def tearDown(self):
        # 停止所有的测试桩
        StubFactory().stop()

        self.driver.quit()

        logging.info("\n============= End to test [ " + self.getDoc() + " ] ===============\n")

对于初始化 deriver 信息,我调用了另外一个类的信息:
这个类 getDriverInfo 中的 androidDriverInfo 方法,如下:

class getDriverInfo():
    '''   获取driver属性信息的类     '''

    def androidDriverInfo(self):
        '''  定义获取driver属性信息的函数--安卓     '''

        desired_caps = desired_capabilities.get_desired_capabilities('Base_2.1.apk')
        #print desired_caps
        #del desired_caps['app']

        driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)

        return driver        

而 desired_capabilities 调用的方法 get_desired_capabilities 代码如下:

def get_desired_capabilities(app):
    desired_caps = {
        'platformName': 'Android',
        'platformVersion': '4.3',
        'deviceName': 'Android Emulator',
        'appPackage' : 'com.xxx.phone',
        'appActivity' : 'com.xxx.ui.FlowPager',
        'app': PATH(r'../testApp/' + app)
    }

    return desired_caps

#5 楼 @strayeagle
不会 python,你贴的也没说明用例执行过程啊……那这样问吧,按你这样调用 getDriverInfo
1、只有两个用例,都没有 UI 操作只打印一条日志,可以顺利执行吗?
2、只有两个用例,第一个用例登录。第二个用例没有 UI 操作只打印一条日志。执行时依次打开哪几个 Activity?
3、只有一个用例,getDriverInfo 后点击 MainPager 上的元素,错误信息是什么?

@strayeagle
用例 3 开头加上这个呢?
driver.start_activity('com.xxx.ui', '.LoginPager')

#7 楼 @sanlengjingvv driver 方法里面没有 start_activity 啊,import 的时候我是 from appium import webdriver,请问你是导入的哪个包啊

#8 楼 @strayeagle 不会 python 啊,我看源码里有这个,按 java 说的话这是个方法不是属性

用例 1【app1】是卸载【app2】
用例 2【app1】安装【app3】
用例 3【app3】登录?

==========
是这样的设计吗?

#10 楼 @umbrella1978 用例中是同一个 app 的:
用例 1 是卸载这个 app;
用例 2 是安装这个 app;
用例 3 是检查用例 2 中安装的 app 登录界面上是否有 pwoerer-by 信息;
用例 4 是登录 app,这个登录依赖的是用例 2 中安装好的 app;
用例 5 是在用例 4 成功登录进入主界面的基础上,去检查这个主界面的侧标栏是否有 powerer-by 信息

#11 楼 @strayeagle 用例 3 中初始化 loginPager 的 driver,用例是分开的,driver 不同无可厚非

有一些应用,在首次安装后启动会有一个引导页,浏览完引导页后才会跳转到登录或者注册页面,再次启动时根据引导页直接打开登录或登录后的主界面,所以首次安装并启动的 Activity 和直接打开登录主页面的 Activity 不一样,需要在 desired_caps 中增加 appWaitActivity,为你想要等待启动的 Android Activity 名称,即引导 activity 后面增加期待使用的 activity,app 界面就可以正常跳转。

#13 楼 @strayeagle 你好,如果需要多个 activity 如何处理呢,添加多个 appWaitActivity 吗,如果是又如何确定顺序呢?

#14 楼 @xjin 这个问题通过查看 webdriver 源码,找到了 wait_activity() 方法,执行用例时如果需要 切换 activity,可以调用这个方法来实现。

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