Appium 新手学 appium-python unittest 如何只运行一次配置项,其他函数按顺序来操作

· 2015年07月06日 · 最后由 lanyou 回复于 2017年03月14日 · 174 次阅读

昨晚凌晨 3 点有人撬我锁,还好我机智,睡之前都锁着的。不然被谋杀了,今天就不能更新帖子了。

狄更斯说:这是最好的时代,也是最坏的时代。我举双手同意。

言归正传,在使用 appium,或者你用 python 来写自动化脚本过程中。有时候我们想只运行一次配置项,appium 是 desired_caps 的一系列配置。webdriver 可能是浏览器初始化的配置。
思考如何把 N 个测试函数按顺序来进行衔接。
而我们会很苦恼,如果用 setup() 跟 teardown() 来进行配置,我想如果你跟我一样实践过,会遇到每个函数都会调用 setup() 跟 teardown(),也就是说,setup() 里你写了 desired_caps 的一系列配置,你很有可能需要重启 app。这对于我们想优化自动化脚本速度和想一连串运行函数的优质 IT 青年而言,简直不能忍
经过花了大量时间搜索以及跟同事的讨论,发现利器,setUpClass() 跟 tearDownClass()。或许我之前没深入了解 unittest 的函数的原因。接下来给 demo。本 demo 为模拟器自带的拨号程序
# -*- coding: utf-8 -*-
#测试报告
import os
import unittest,sys,time,re,datetime,HTMLTestRunner
from appium import webdriver
from time import sleep
import sys
#reload(sys)
#sys.setdefaultencoding('utf-8')
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

# Returns abs path relative to this file and not cwd
PATH = lambda p: os.path.abspath(
    os.path.join(os.path.dirname(__file__), p)
)


class ContactsAndroidTests(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        print 'setUpClass'
        desired_caps = {}
        desired_caps['platformName'] = 'Android'
        desired_caps['platformVersion'] = '4.4'
        desired_caps['deviceName'] = '192.168.56.101:5555'
        desired_caps['appPackage'] = 'com.android.dialer'
        desired_caps['appActivity'] = '.DialtactsActivity'

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

    @classmethod
    def tearDownClass(cls):
        cls.driver.close_app()
        cls.driver.quit()
        print 'tearDownClass'

    def setUp(self):
        print "setup"

    def tearDown(self):
        print 'teardown'

    def test_add_contacts(self):
        print 1
        #def test_B(self):
        self.driver.find_element_by_id('com.android.dialer:id/call_history_button').click()

    def test_A(self):
        print 2
        self.driver.find_element_by_class_name("android.app.ActionBar$Tab").click()


if __name__ == '__main__':
    #unittest.main(exit=False)
    suite = unittest.TestSuite()
    suite.addTest(ContactsAndroidTests("test_add_contacts"))
    suite.addTest(ContactsAndroidTests("test_A"))
    #suite.addTest(IposCase("testmaters"))
    timestr = time.strftime('%Y%m%d%H%M%S',time.localtime(time.time()))
    filename = "D:\\appium\\appiumresult\\result_" + timestr + ".html"
    print (filename)
    fp = open(filename, 'wb')
    runner = HTMLTestRunner.HTMLTestRunner(
                stream=fp,
                title='测试结果',
                description='测试报告'
                )
    #suite = unittest.TestLoader().loadTestsFromTestCase(ContactsAndroidTests)
    #unittest.TextTestRunner(verbosity=2).run(suite)
    runner.run(suite)
    #g_browser.quit()
    fp.close() #测试报告关闭
而我的测试报告如下图


ps:最近睡觉都在思考如何解决脚本上的问题,睡眠质量好差

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 87 条回复 时间 点赞

请问这个报告是用 HTMLTestRunner 吗?

#88 · 2015年07月07日 Author

#1 楼 @halo_lan 代码很明显了。。

额, unittest 的官方文档里是有提到 setUpClass() 这些的,而且 unittest 可以用到的方法远不止 setUp,tearDown 这些。

学习 unittest 最快的路还是去把官方文档都看一遍,不求都会用,但至少需要知道有哪些方法可以用,直接实战 +google 的方法是流沙上建房子,埋的坑只会越来越多。

之前不是跟你说了,用 java 可以秒杀吗? 还有你这测试报告给你们主管看,主管看了不会影响他的审美观吗?

#85 · 2015年07月07日 Author

#4 楼 @tspring 为什么会影响审美观,testng 的测试报告我也没觉得多好看

84楼 已删除
#83 · 2015年07月09日 Author

#6 楼 @123456_ 真心不想看你的代码

#9 楼 @yangxiangfu 呵呵 我干嘛。。。

我执行了不行呢,提示没有定义 drvier

#77 · 2015年07月14日 Author

#12 楼 @test882012 哎,你先把基础打好吧

楼主,问下你用的 IDE 是啥

#75 · 2015年07月31日 Author

#14 楼 @tasidingge pycharm 啊

写的非常好

把 set_up 的方法里面的内容拿到上面类的外面去,作为一个全局变量。不封装在函数和类内

#72 · 2015年08月03日 Author

#17 楼 @julian1610 。。。。

我的测试报告,python 的,应该美观点


#71 · 2015年08月11日 Author

#19 楼 @strayeagle 牛逼,怎么做的

Traceback (most recent call last):
  File "test_1.py", line 66, in <module>
    fp = open(filename, 'wb')
FileNotFoundError: [Errno 2] No such file or directory: 'E:\\testspace\\appiumresult\\result_2015102

求解....

#69 · 2015年10月23日 Author

#21 楼 @tlbin 你这个文件夹要先手工创建的

cls.driver 和 self.driver 不是一个对象,可以这么用么?

#21 楼 @turinblueice 哦,可以,instance 如果自己不对属性赋值的话,继承类的同名属性。

#66 · 2015年11月13日 Author

#24 楼 @turinblueice 。。。。。自言自语?

#65 · 2015年11月13日 Author

#24 楼 @turinblueice 你 qq 号多少啊

#26 楼 @mads 确实是要创建一个文件夹 但又开始报 py3 引入 HTMLTestTunner 的错了

Traceback (most recent call last):
  File "test_1.py", line 74, in <module>
    runner.run(suite)
  File "E:\python\lib\HTMLTestRunner.py", line 628, in run
    test(result)
  File "E:\python\lib\unittest\suite.py", line 84, in __call__
    return self.run(*args, **kwds)
  File "E:\python\lib\unittest\suite.py", line 114, in run
    self._handleClassSetUp(test, result)
  File "E:\python\lib\unittest\suite.py", line 170, in _handleClassSetUp
    self._addClassOrModuleLevelException(result, e, errorName)
  File "E:\python\lib\unittest\suite.py", line 216, in _addClassOrModuleLevelException
    result.addError(error, sys.exc_info())
  File "E:\python\lib\HTMLTestRunner.py", line 584, in addError
    output = self.complete_output()
  File "E:\python\lib\HTMLTestRunner.py", line 558, in complete_output
    return self.outputBuffer.getvalue()
AttributeError: '_TestResult' object has no attribute 'outputBuffer'
#63 · 2015年11月13日 Author

#27 楼 @tlbin 换 2.7 试试。。。

#61 · 2015年11月13日 Author

#29 楼 @tlbin 我不用 3 的。。。用 2.7

#25 楼 @mads 刚接触这个,所以研究研究,这个类成员和对象成员在 python 里面和其他 c、c++不太一样

#58 · 2015年11月13日 Author

#32 楼 @turinblueice 怎么私信。。。

57楼 已删除

我也刚刚接触。。看你的 DEMO 感觉好深奥哦。。我朋友说这个框架相对于简单好用,是真的么?

@mads
我是 python 2.7 。但是执行测试时,也报了这个错误:
AttributeError: '_TestResult' object has no attribute 'outputBuffer'

请问,是什么原因呢,怎么解决呢。排错了很久,也无解
谢谢

#27 楼 @tlbin
我是 python 2.7 。但是执行测试时,也报了和你一样同样的错误:
AttributeError: '_TestResult' object has no attribute 'outputBuffer'

请问,你是怎么解决的呢。我排错了很久,也无解
谢谢

#37 楼 @xiaoxu790 我扔那了 还没管····你 py2 可以找楼主 哈哈 @mads

python3-----修改下 HTMLTestRunner 源码-http://www.bubuko.com/infodetail-529431.html

#51 · 2016年01月04日 Author

#39 楼 @new 你玩吧,我 N 久不玩了

#39 楼 @new 我就这么改的 然后还是之前我贴图的错

49楼 已删除

你好,我是这么做的,但是只运行了 setUpClass 和 tearDownClass,用例都没执行

不知道是什么原因啊

#47 · 2016年01月05日 Author

#43 楼 @xzhan 把我代码贴过去看看。。。

#44 楼 @mads 我就是贴的你的代码,只不过把参数和用例改成了我的。。

#45 · 2016年01月05日 Author

#45 楼 @xzhan 用例名是谁的。。。你的还是我的

#46 楼 @mads 开始改的我自己的,后来试过完全用你的,都不行。。我用的 python3.4,查了下 unittest 文档, setUP 和 tearDown 这块和 2 没什么区别吧?

#43 · 2016年01月05日 Author

#47 楼 @xzhan 我用的是 2.7,不用 3

AttributeError: '_TestResult' object has no attribute 'outputBuffer' 的错有人解了吗。。。

#49 楼 @kesha0 你这个错误解决了吗

#50 楼 @mymgbaby 解了,不用 setUpClass,直接把初始化的语句写在 Class 里面

#51楼 @kesha0 class AppKeyWord(unittest.TestCase, AppExecuteKeyword.Key,Driver.MyDriver,AppiumServer.AppiumServer):
    @classmethod
    def setUpClass(cls):
        print 'setUpClass'
        cls.driver =cls.get_driver()

    @classmethod
    def tearDownClass(cls):
        cls.driver.close_app()
        cls.driver.quit()

        print 'tearDownClass'

    def setUp(self):

        # 在测试过程中打开任意活动
        # driver.start_activity(app_package, app_activity)
        self.verificationErrors = []

    def action(self,case_id, case_name):
        self.AppExecute(case_id, case_name)
        print "finish case"

    @staticmethod
    def getTestFunc(case_id, case_name):
        def func(self):
            self.action(case_id, case_name)
        return func

    def tearDown(self):
        print "-"*70
        print u"用例运行成功"
        time.sleep(5)
        self.assertEqual([], self.verificationErrors)

没懂你的意思,这个是我的初始化代码,要怎么改

#52 楼 @mymgbaby
亲测不用 setUpClass 就没问题,原因是什么我也不清楚

# -*- coding: utf-8 -*-
#测试报告
import os
import unittest,sys,time,re,datetime,HTMLTestRunner
from appium import webdriver
from time import sleep
import sys
#reload(sys)
#sys.setdefaultencoding('utf-8')
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

# Returns abs path relative to this file and not cwd
PATH = lambda p: os.path.abspath(
    os.path.join(os.path.dirname(__file__), p)
)


class ContactsAndroidTests(unittest.TestCase):

    desired_caps = {}
    desired_caps['platformName'] = 'Android'
    desired_caps['platformVersion'] = '4.4'
    desired_caps['deviceName'] = '192.168.56.101:5555'
    desired_caps['appPackage'] = 'com.android.dialer'
    desired_caps['appActivity'] = '.DialtactsActivity'
    cls.driver = webdriver.Remote('http://127.0.0.1:4723/wd/hub', desired_caps)

    def setUp(cls):
        cls.driver.start_avtivity('com.android.dialer','.DialtactsActivity')

    def tearDown(cls):
        print 'teardown'

    def test_add_contacts(cls):
        print 1
        #def test_B(cls):
        cls.driver.find_element_by_id('com.android.dialer:id/call_history_button').click()

    def test_A(cls):
        print 2
        cls.driver.find_element_by_class_name("android.app.ActionBar$Tab").click()


if __name__ == '__main__':
    #unittest.main(exit=False)
    suite = unittest.TestSuite()
    suite.addTest(ContactsAndroidTests("test_add_contacts"))
    suite.addTest(ContactsAndroidTests("test_A"))
    #suite.addTest(IposCase("testmaters"))
    timestr = time.strftime('%Y%m%d%H%M%S',time.localtime(time.time()))
    filename = "D:\\appium\\appiumresult\\result_" + timestr + ".html"
    print (filename)
    fp = open(filename, 'wb')
    runner = HTMLTestRunner.HTMLTestRunner(
                stream=fp,
                title='测试结果',
                description='测试报告'
                )
    #suite = unittest.TestLoader().loadTestsFromTestCase(ContactsAndroidTests)
    #unittest.TextTestRunner(verbosity=2).run(suite)
    runner.run(suite)
    #g_browser.quit()
    fp.close() #测试报告关闭
    ContactsAndroidTests.driver.quit()

#19 楼 @strayeagle 报告模版自己写的么?

#36 · 2016年06月16日 Author

#54 楼 @silentteamo import HTMLTestRunner。。。

请问我按你的来了但是 出现这样的错误

#34 · 2016年07月12日 Author

#56 楼 @y693055797 哎,你是不是用 selenium 的包了

#57 楼 @mads 是的 换成 appium 的包 我试试

#57 楼 @mads 是不是这种方法 中间一个用例处错误后 后面的就无法继续进行了 全部报错的

#31 · 2016年07月12日 Author

#59 楼 @y693055797 不会啊,错误是啥错误哦

#60 楼 @mads 就是 我中间有一个 assert 的 没通过 这样
他就直接 跳出来 停止测试了 后来我把 这句断言删了

#29 · 2016年07月12日 Author

#61 楼 @y693055797 你是啥意思。单个函数的 assert 就是这么设计的,失败接下来的步骤也不能运行了。但是不影响接下来的其他函数

#62 楼 @mads 接下来的 def 中的用例 也不运行 是正确的吗 那我想实现 这个不通过 但是我想让他继续进行下一个用例(保证下一个的用例还是能够进行的比如 控件仍然能点击) 这样能实现吗

#27 · 2016年07月12日 Author

#63 楼 @y693055797 接下来的用例不运行,就是你自己脚本的问题了。我是可以继续运行的

#26 · 2016年07月12日 Author

#63 楼 @y693055797 因为是继续上一次失败的 UI 的操作,所以你得考虑上一次失败后如何跟下一个用例进行衔接

#65 楼 @mads 不过我现在又出现问题 突然脚本打开 activity 后 不继续进行了
一直停在主界面 而且 cls.driver.close_app() 这也出现错误 ,,

#24 · 2016年07月13日 Author

#66 楼 @y693055797 啥意思。。。重启电脑重新跑

#67 楼 @mads 重启过了 就是打开 activity 后 不继续按我写的脚本点击 就一直停在那 过一会才会提示出错
WebDriverException: Message: UiAutomator died while responding to command, please check appium logs!

#64 楼 @y693055797 就显示这 不往下点击

#21 · 2016年07月13日 Author

#69 楼 @y693055797 。。我咋知道。。你应该把代码贴出来,报错贴出来有啥用。。

#70 楼 @mads #-- coding: UTF-8 --

# 从这里开始 这是我敲的
import os
import unittest,time,re,datetime,HTMLTestRunner
from appium import webdriver
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

PATH=lambda p:os.path.abspath(
os.path.join(os.path.dirname(file),p)

)

class LoginAndroidTests(unittest.TestCase):

@classmethod
def setUpClass(cls):
print 'setUpClass'
desired_caps={}
desired_caps['device'] = 'android'
desired_caps['platformName']='Android'
desired_caps['browserName']=''
desired_caps['version']='5.1.1'
desired_caps['deviceName']='061f49d4e302964a'
desired_caps['appPackage']='xxxxx'
desired_caps['appActivity']='xxxx.ui.screen.HomeActivity'
desired_caps['noSign'] = 'true'

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

@classmethod
def tearDownClass(cls):
cls.driver.close_app()
cls.driver.quit()
print 'tearDownClass'

def setUp(self):
print "setup"

def tearDown(self):
print 'teardown'

def test_1login(self):
print 1
time.sleep(5)

name= self.driver.find_element_by_id('Id')
name.click()
name.send_keys('admin')

time.sleep(3)

这样的 就是不执行点击操作

#18 · 2016年07月13日 Author

#71 楼 @y693055797 能不能用代码块。。

#16 · 2016年07月13日 Author

#73 楼 @y693055797 你的 if name == 'main':呢。。。

#15 · 2016年07月13日 Author

#73 楼 @y693055797 你最好再看下自己的代码结构,没有主函数的。。

#75 楼 @mads 突然又好了 应该是我们公司的这个 apk 的毛病😹

#75 楼 @mads 请问 appium 不支持有系统权限的 apk 吗 我发现我们公司这个 apk 只要配置成 油系统权限的后 就不能执行点击操作了

#19 楼 @strayeagle 请问报告中 case 的中文是怎么加上的

#79 楼 @mads 就是生成的报告中 case 带中文 如图

#10 · 2016年07月15日 Author

"""啊啊啊 “”“”

#8 · 2016年07月15日 Author

#82 楼 @y693055797 就这么写啊

def A():
  """啊啊啊啊啊啊啊啊"""

#83 楼 @mads 哦哦 就注释啊 明白了 还有问题 请教下 我的 pycharm 为什么 按 ALT+SHIFT+F10 后 没有自己的脚本名字的选项

#6 · 2016年07月15日 Author

#84 楼 @y693055797 我不按这个玩意的

#85 楼 @mads 那 run unittests 就不会生成报告 。。。只会在这有,

#4 · 2016年07月15日 Author

#86 楼 @y693055797 来吧,来互相伤害

#87 楼 @mads 😅 解决了 那个问题 不过我这里为什么有时候 用例结束后 不会关闭 app,,

#2 · 2016年07月18日 Author

#88 楼 @y693055797 来吧,来互相伤害

strayeagle 回复

大神,你的报告源码可否共享一下?膜拜!💪

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