Macaca 准备这样使用 Macaca 做 UI 自动化测试,还请各位前辈看看这种形式是否合适

王华林 · 2017年02月19日 · 最后由 王华林 回复于 2018年03月14日 · 2509 次阅读

先行声明:
1、下面展示的内容多源于 TesterHome 各位前辈的经验总结,我只是按照我的想法进行了简单拼接(目前只适用于 Win 平台下的 Android 自动化测试)
2、主要参考了@tongshanshanshan老师的https://testerhome.com/topics/6810
3、所用语言为 Python,测试报告模板使用了 HTMLTestRunner.py,并稍事修改以方便截图、日志打印。所下载的 HTMLTestRunner.py(已在原作者之上做了修改)来源于何处不明
4、DEMO 工程已上传 GitHub“https://github.com/Hualiner/UI-auto-test-base-macaca
5、若直接使用需自行安装 “金惠家” App,且需要在 Account.py 中添加正确的用户名和密码

当前工作内容有自动化测试的需要,先期准备开展 UI 自动化测试。通过对比,最终选择了@xdf达峰老师团队的 Macaca。受之前单位的测试总工的影响,准备这样使用 Macaca 做 UI 自动化测试,还请各位前辈看看这种形式是否合适。

工程目录如下:
1、其中 CarInsurance 为某一特定的业务线
2、Public 为所有业务线通用的东西

UI 自动化测试用例:
1、采用 PageObject 模式,将测试用例、页面定位进行分离(TestCase、PageObject)
2、采用测试数据参数化,将测试用例、测试数据分离(TestCase、TestData)
3、自动化测试用例放在 TestSuite_xxxx 下的 TestCase 里面,通过 run_all_cases.bat 执行特定业务线下所有的 TestSuite_xxxx 中的用例,通过 run_cases.bat 执行对应的 TestSuite_xxxx 中的用例

Public:
1、为了使自动化用例编写者编写自动化用例时只需关注用例逻辑、元素定位、测试数据,所以写了一个 Public
2、其中,PageObject 中包含了 BasePage(后面介绍它的作用)以及公用的页面
3、Public 里面的 py 文件则包含了 macaca server 启动、多设备、测试报告、日志打印、错误截图等功能

上面介绍了我准备开展的 UI 自动化测试的一个总的结构,下面简单介绍一下流程:
1、通过类似 run_cases.bat 的批处理作为入口进行 UI 自动化测试

if __name__ == '__main__':
    cs = CaseStrategy()
    cases = cs.collect_cases(suite=True)

    # in future, cases_list may be used for testing strategy in multi devices
    Drivers().run(cases)

2、还没考虑好多设备时用例分配策略,所以目前的实现是,同一台 PC 连接的所有设备跑一样的用例(CaseStrategy())
3、macaca server 的开启、以及 driver 的初始化是通过 Drivers() 来完成的,如下代码:

class Drivers:
    @staticmethod
    def _run_cases(server_url, run, cases):
        log = Log()
        log.set_logger(run.get_device()['udid'], run.get_path() + '\\' + 'client.log')

        log.i('platformName: %s', run.get_device()['platformName'])
        log.i('udid: %s', run.get_device()['udid'])
        log.i('package: %s\n', run.get_device()['package'])

        log.i('macaca server port: %d\n', run.get_port())

        # init driver
        driver = WebDriver(run.get_device(), server_url)
        driver.init()

        # set cls.path, it must be call before operate on any page
        path = ReportPath()
        path.set_path(run.get_path())

        # set cls.driver, it must be call before operate on any page
        base_page = BasePage()
        base_page.set_driver(driver)

        # skip wizard
        if skip_wizard_to_home():
            # run cases
            run.run(cases)

        # quit driver
        driver.quit()

    def run(self, cases):
        # read all devices on this PC
        devices = Devices().get_devices()

        # read free ports on this PC
        ports = Ports().get_ports(len(devices))

        if not len(devices):
            print('there is no device connected this PC')
            return

        runs = []
        for i in range(len(devices)):
            runs.append(RunCases(devices[i], ports[i]))

        # start macaca server
        macaca_server = MacacaServer(runs)
        macaca_server.start_server()
        for port in ports:
            while not macaca_server.is_running(port):
                print('wait macaca server all ready...')
                time.sleep(1)
        print('macaca server all ready')

        # run on every device
        pool = Pool(processes=len(runs))
        for run in runs:
            pool.apply_async(self._run_cases,
                             args=(macaca_server.server_url(run.get_port()), run, cases,))

            # fix bug of macaca, android driver can not init in the same time
            time.sleep(2)

        pool.close()
        pool.join()

4、上面的多设备是采用的@tongshanshanshan老师的https://testerhome.com/topics/6810中的代码
5、Drivers().run() 中有一个 RunCases(),它主要是设置了每个设备 UI 自动化时设备信息、macaca server 端口、存放测试报告/日志/截图的路径,以及最终通过 HTMLTestRunner 来执行用例,如下代码:

class RunCases:
    def __init__(self, device, port):
        self.test_report_root = '.\\TestReport'
        self.device = device
        self.port = port

        if not os.path.exists(self.test_report_root):
            os.mkdir(self.test_report_root)

        date_time = time.strftime('%Y-%m-%d_%H_%M_%S', time.localtime(time.time()))
        self.test_report_path = self.test_report_root + '\\' + date_time + '-%s' % self.device['udid']
        if not os.path.exists(self.test_report_path):
            os.mkdir(self.test_report_path)

        self.file_name = self.test_report_path + '\\' + 'TestReport.html'

    def get_path(self):
        return self.test_report_path

    def get_device(self):
        return self.device

    def get_port(self):
        return self.port

    def run(self, cases):
        with open(self.file_name, 'wb') as file:
            runner = HTMLTestRunner(stream=file, title='自动化测试报告', description='用例执行情况:')
            runner.run(cases)

6、每个设备(进程)跑的用例是由 Driver()._run_cases() 完成的,在这里面,主要做了每个设备 UI 自动化测试的准备工作,包括每个 macaca client 的 log 配置、测试报告路径的配置、BasePage 中的 driver 配置,以及真正开始自动化测试
7、第 6 点中提到的配置之所以要在这里进行,是因为我采用了@classmethod下的 cls,这样可以解决一个进程中该类只需配置一次,后面的该类的对象可以不用再做配置,如下代码:

class Log:
    @classmethod
    def set_logger(cls, udid, file):
        logger = logging.getLogger('MACACA')
        logger.setLevel(logging.INFO)

        fh = logging.FileHandler(file)
        fh.setLevel(logging.INFO)

        ch = logging.StreamHandler()
        ch.setLevel(logging.INFO)

        formatter = logging.Formatter('%(asctime)s'
                                      + ' - %s' % udid
                                      + ' - %(levelname)s'
                                      + ' - %(message)s')

        fh.setFormatter(formatter)
        ch.setFormatter(formatter)

        logger.addHandler(fh)
        logger.addHandler(ch)

        cls.logger = logger
class ReportPath:
    @classmethod
    def set_path(cls, ps):
        cls.path = ps

    def get_path(self):
        return self.path
class BasePage(object):
    @classmethod
    def set_driver(cls, dri):
        cls.driver = dri

    def get_driver(self):
        return self.driver

8、通过第 7 点中的方法,就解决了一个进程中(但设备)每个 Page 继承 BasePage 后都有一个特定的 driver,如下代码:

class MyCarInsurancePage(BasePage):
    @teststep
    def wait_page(self):
        """以“我的车辆”的XPATH为依据"""
        try:
            self.driver\
                .wait_for_element_by_xpath('//android.widget.FrameLayout[1]/android.widget.LinearLayout[1]'
                                           '/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]'
                                           '/android.widget.FrameLayout[1]/android.widget.LinearLayout[1]'
                                           '/android.view.ViewGroup[1]/android.webkit.WebView[1]'
                                           '/android.webkit.WebView[1]/android.view.View[12]')
            return True
        except WebDriverException:
            return False

9、每条用例头带有@testcase这个装饰器,以便在 console 以及 client.log 中显示与记录以及错误后的截图等操作,如下代码:

@testcase
def test_Car_MyCarInsurEntry_Func_010(self):
    """我的车险入口验证"""
    self.home_page.click_my()

    login = LoginPage()
    if login.wait_page():
        login.input_account(VALID_ACCOUNT.account())
        login.input_password(VALID_ACCOUNT.password())
        login.login()

        gesture = GesturePasswordPage()
        if gesture.wait_page():
            gesture.skip()

        if self.home_page.wait_page():
            self.home_page.click_my()

    my_page = PlatformAppMyPage()
    my_page.wait_page()
    my_page.click_my_car_insurance()

    my_car_insurance = MyCarInsurancePage()
    self.assertTrue(my_car_insurance.wait_page())

10、每个测试步骤都带有这样的@teststep装饰器,以便在 console 以及 client.log 中显示与记录以及错误后的截图等操作,如下代码:

@teststep
def input_account(self, account):
    """以“请输入手机号码”的TEXT为依据"""
    self.driver\
        .element_by_name('请输入手机号码')\
        .clear()\
        .send_keys(account)

11、在 Decorator() 中有@testcase@teststep这样的装饰器用例执行日志打印、错误后的处理(当前只有截图),代码如下:

def _screenshot(name):
    date_time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
    screenshot = name + '-' + date_time + '.PNG'
    path = ReportPath().get_path() + '\\' + screenshot

    driver = BasePage().get_driver()
    driver.save_screenshot(path)

    return screenshot

def teststep(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        try:
            log.i('\t--> %s', func.__qualname__)
            ret = func(*args, **kwargs)
            return ret
        except WebDriverException:
            log.e('\t<-- %s, %s', func.__qualname__, 'Error')
            raise WebDriverException(message=flag + _screenshot(func.__qualname__))

    return wrapper

def testcase(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        try:
            log.i('--> %s', func.__qualname__)
            ret = func(*args, **kwargs)
            log.i('<-- %s, %s\n', func.__qualname__, 'Success')
            return ret
        except WebDriverException:
            log.e('<-- %s, %s\n', func.__qualname__, 'Error')
            raise WebDriverException
        except AssertionError:
            log.e('<-- %s, %s\n', func.__qualname__, 'Fail')
            raise AssertionError(flag + _screenshot(func.__qualname__))

    return wrapper

执行过程的日志如下图:

某个特定设备的测试报告路径下的内容如下图:

HTMLTestRunner 生成的测试报告如下图:

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

这的很用心,点赞

—— 来自 TesterHome 官方 安卓客户端

目前正在考虑 UI 自动化要不要换成用 macaca,LZ 这篇介绍的挺详细的的,正好学习了,感谢分享。

王华林 [该话题已被删除] 中提及了此贴 02月22日 09:06

请问 HTMLTestRunner 生成的报告的截图路径如何写入的

重来看雨 回复

我的报告和截图是放在同一目录下的

如下,path = ReportPath().get_path() + '\' + screenshot 中的 ReportPath().get_path() 就是报告的存放路径(同时也是截图的存放路径)。通过 raise WebDriverException(message=flag + screenshot(func.qualname_)) 这样的异常,在异常信息中把截图名称给出(用 flag 变量中的'IMAGE:'标记,截图名为 screenshot = name + '-' + date_time + '.PNG')。

flag = 'IMAGE:'

def _screenshot(name):
    date_time = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
    screenshot = name + '-' + date_time + '.PNG'
    path = ReportPath().get_path() + '\\' + screenshot

    driver = BasePage().get_driver()
    driver.save_screenshot(path)

    return screenshot


def teststep(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        try:
            log.i('\t--> %s', func.__qualname__)
            ret = func(*args, **kwargs)
            return ret
        except WebDriverException:
            log.e('\t<-- %s, %s', func.__qualname__, 'Error')
            raise WebDriverException(message=flag + _screenshot(func.__qualname__))

    return wrapper

由于上面的异常信息中已经给出了截图的名称,因此,在 HTMLTestRunner.py 中 image = image[image.find("IMAGE:")+6:(int(image.find("PNG"))+3)] 就可以把截图名拿出来(截图后缀为.PNG)。这样的话,因为报告和截图在同一个目录下,所以这里只需要知道截图名称就可以。

def _generate_report_test(self, rows, cid, tid, n, t, o, e):
    # e.g. 'pt1.1', 'ft1.1', etc
    has_output = bool(o or e)
    tid = (n == 0 and 'p' or 'f') + 't%s.%s' % (cid+1,tid+1)
    name = t.id().split('.')[-1]
    doc = t.shortDescription() or ""
    desc = doc and ('%s: %s' % (name, doc)) or name
    tmpl = has_output and self.REPORT_TEST_WITH_OUTPUT_TMPL or self.REPORT_TEST_NO_OUTPUT_TMPL

    # o and e should be byte string because they are collected from stdout and stderr?
    if isinstance(o,str):
        # TODO: some problem with 'string_escape': it escape \n and mess up formating
        # uo = unicode(o.encode('string_escape'))
        uo = e
    else:
        uo = o
    if isinstance(e,str):
        # TODO: some problem with 'string_escape': it escape \n and mess up formating
        # ue = unicode(e.encode('string_escape'))
        ue = e
    else:
        ue = e

    script = self.REPORT_TEST_OUTPUT_TMPL % dict(
        id = tid,
        output = saxutils.escape(uo),
        # output=saxutils.escape(uo + ue),
    )
    image = self.REPORT_TEST_OUTPUT_IMAGE % dict(
        screenshot = saxutils.escape(uo)
        # screenshot = saxutils.escape(uo + ue)
    )
    caseid = self.REPORT_TEST_OUTPUT_CASEID % dict(
        case_id = saxutils.escape(uo)
        # case_id = saxutils.escape(uo + ue)
    )
    row = tmpl % dict(
        tid = tid,
        Class = (n == 0 and 'hiddenRow' or 'none'),
        style = n == 2 and 'errorCase' or (n == 1 and 'failCase' or 'none'),
        desc = desc,
        script = script,
        image = image[image.find("IMAGE:")+6:(int(image.find("PNG"))+3)],
        caseid = caseid[caseid.find("case"):(int(caseid.find("case"))+9)],
        status = self.STATUS[n],
    )
    rows.append(row)
    if not has_output:
        return
王华林 回复

借了您的 HTMLTestRunner 模块,并在您上面的解说下,我也成功把断言失败的截图搞到 HTML 报告了,十分感谢您的开源.
因为我的整体结构不一样,截图是在报告的子目录下,如下图:

所以 截图搞到报告的实现有所不同,我在 HTMLTestRunner 模块 添加了一个方法:

    row = tmpl % dict(
        tid = tid,
        Class = (n == 0 and 'hiddenRow' or 'none'),
        style = n == 2 and 'errorCase' or (n == 1 and 'failCase' or 'none'),
        desc = desc,
        script = script,
        #image = image[image.find("IMAGE:")+6:(int(image.find("PNG"))+3)],
        image = self.a(desc),
        caseid = caseid[caseid.find("case"):(int(caseid.find("case"))+9)],
        status = self.STATUS[n],
    )
    rows.append(row)
    if not has_output:
        return
def a(self,cd):

    day = strftime('%Y-%m-%d')
    path = '/Users/zhaozhiquan/automation/iOSSdk/result/' + day + '/screencap'
    cd = cd.split(':') #获取到case id后进入分割
    cd =cd[0]+'.png'   #并组合好 截图名称
    a = os.listdir(path)
    if cd in a:
        b = a.index(cd) #然后判断的出 list a的索引
        return path+'/'+a[b]

方法解析:image = self.a(desc),调用 def a(self,cd),获取到了 case id,并以 ‘ :’ 进行分割(test_101: 查看用户协议),并组合成截图的名称,然后通过 os 模块的 listdir(),去获取 screencap 文件夹下的所以文件名称,返回一个 list,然后通过 组合完成截图名称的 CD,去判断,cd 是否 in list a, 如果在,则获取到 截图 的索引 b,return 一个完整的 截图 path.
下图是报告:

再次感谢。

重来看雨 回复

很棒啊!😉

后面的话,可以把 path = '/Users/zhaozhiquan/automation/iOSSdk/result/' + day + '/screencap'这里面的绝对路径修改一下,这样他人使用你的脚本的时候才不会有问题。

王华林 回复

已经改好了。。都是相对路径了

def a(self,cd):
    day = strftime('%Y-%m-%d')
    path = './result/' + day + '/screencap'
    cd = cd.split(':') #拿到case id后进入分割
    cd =cd[0]+'.png'   #并组合好 截图名称
    a = os.listdir(os.getcwd()+os.sep+path)
    if cd in a:
        b = a.index(cd) #然后判断的出 list a的索引
        return 'screencap/'+a[b]
重来看雨 回复

👍

王华林 回复

😁 把 result 文件夹发送到别的 pc,也正常看到截图

重来看雨 回复

要的就是这效果😉

@466895041 欢迎 github 分享

xdf 回复

好了

xdf 回复

多谢达峰老师推荐!

@Hualiner 你在 qq 群里吗?

xdf 回复

不在

287162474 加一下

xdf 回复

已加

重来看雨 回复

你好,可以加你 qq 请教一下么,不知道是哪有问题,截图一直弄不出来

cake 回复

找到原因了😅

cake 回复

这么快就搞定,,。。厉害😁

你好,clone 了您的 DEMO 工程 GitHub“https://github.com/Hualiner/UI-auto-test-base-macaca” 导入后,执行 run_all_cases.py 完成后,未发现有生成 TestReport 文件夹 (应含截图、log、.html),是 DEMO 中存放 TestRepor 设置路径有问题么😅

小王子 回复

我留意到这个

请问你的电脑是 Windows?还是其他系统?

王华林 回复

Ubuntu16.04,不支持么😀

小王子 回复

我在 Windows 上面使用的,我想可能是 Public/RunCases 中的问题(如下文件路径,Windows 与 Ubuntu 有点区别),你应该可以解决的😃

class RunCases:
    def __init__(self, device, port):
        self.test_report_root = '.\\TestReport'
        self.device = device
        self.port = port

        if not os.path.exists(self.test_report_root):
            os.mkdir(self.test_report_root)

        date_time = time.strftime('%Y-%m-%d_%H_%M_%S', time.localtime(time.time()))
        self.test_report_path = self.test_report_root + '\\' + date_time + '-%s' % self.device['udid']
        if not os.path.exists(self.test_report_path):
            os.mkdir(self.test_report_path)

        self.file_name = self.test_report_path + '\\' + 'TestReport.html'
小王子 回复

另外,Public/Ports 里面,你也得稍微改一下

class Ports:
    @staticmethod
    def is_using(port):
        """判断端口号是否被占用"""
        # Mac OS
        # cmd = "netstat -an | grep %s" % port

        # Windows
        cmd = "netstat -an | findstr %s" % port

        if os.popen(cmd).readlines():
            return True
        else:
            return False
王华林 回复

😁 😁 好哒,多谢提醒,全部搞定。

小王子 回复

👍

重来看雨 回复

大神,你用的 Py 是哪个版本的?可以把你改好的 HtmlTestRunner 源码共享一下吗?非常感谢😀

lanyou 回复

上面有地址。。你去下载吧。。

40楼 已删除
41楼 已删除

下载 Demo 工程来运行,但是为什么运行不起呢。

天堂鸟 回复

你是否清楚流程?如果清楚的话,你在流程中间加写打印看看。

在 Public 里面的 Drivers.py 中加打印,看你的截图是过了 macaca_server.start_server(),然后你看看后面的流程哪儿出了问题

王华林 回复

谢谢你的回复,今天我看了,是测试用例的列表没有取到,所以直接跳过测试用例执行了。
请问你的 Python 版本是多少呢,我现在用的 3.3.5。
直接运行 CaseStrategy 的时候报了这样的错,没有找到解决的办法。raise ImportError('Start directory is not importable: %r' % start_dir)
ImportError: Start directory is not importable ................\TestCase' 不知道和 Python 的版本有没有关系。

天堂鸟 回复

我用的 Python3.6,按理说没有什么差别。要不你加我 QQ,我远程看看?

王华林 回复

嗯 我刚刚换了 3.6,好像确实是没有差别,改成了以下的代码,
先找到匹配 test_的 py 文件,然后再找到父目录用 discover 方法。
import os
import os.path
import re
import unittest

casepaths = []

class CaseStrategy:
def init(self):
self.casepaths = []

def createsuite(self):
for parent, dirnames, filenames in os.walk('..'):

for filename in filenames:
# print "parent is:" + parent
# print "filename is:" + filename
path = os.path.join(parent, filename)
# 正则判断是否为测试用例
match = re.match('test_', filename)
if match:
print (u"获取测试用例目录:%s" % parent)
casepaths.append(parent)
break

testunit = unittest.TestSuite()
# discover 方法定义
for casepath in casepaths:
discover = unittest.defaultTestLoader.discover(
casepath,
pattern='test_*.py'
)
for test_suite in discover:
for test_case in test_suite:
testunit.addTest(test_case)
print (testunit)
return testunit

if name == 'main':
cs = CaseStrategy()
cs.createsuite()

你好,一个很多按钮页面,我用 BasePage 里的 find_element_by_swipe_up 滑动到底之后,再用 swipe_down 往上滑结果就划不动,直接点击了页面最下端某一个按钮,log 里面查不到信息?请问有遇到这种情况吗?

Bach 回复

我不清楚你使用这两个方法使用的参数/具体情况如何,所以无法给出合理的解答。如果你对这两个方法的过程有疑问,你可以在这两个方法里面加上打印看看。另外,为了快速调试,可以使用 https://testerhome.com/topics/7854 中的方式来调试

王华林 回复

好的,谢谢。麻烦再问一个问题,安卓机测试的时候,autoAcceptAlerts 我写在了 devices.py 里,对引导页 WizardPage 的 Alerts 能生效,进了 App 的 Homepage 页的就没用了。
打印的 log 里面也显示生效了,2017-05-08 17:42:22,776 - B2T7N16818009539 - INFO - autoAcceptAlerts: True

Bach 回复

至于 autoAcceptAlerts 的功能是 Macaca 本身的实现的,你所说的未对 Homepage 的 Alerts 生效,这个我就不清楚了。另外,问一下,你所说的 Homepage 的 Alerts 是什么样的形式?是 Android 系统给出的?还是应用给出的?

王华林 回复

系统的 Alerts, 获取位置权限等用的,以前这些 Alerts 在引导页的,这几天 app 改成进 app 首页再弹了,就不能自动确认了

Bach 回复

你问一下其他人 autoAcceptAlerts 的使用场景吧,这个我用得不多。另外,你可以在脚本里面直接跳过这个弹窗。

再打扰一下,请问 testReport.html 文件里面的截图为什么显示不了,我看文中截图也有这个情况。
//已经弄明白了,html 文件路径有点问题。

看了好久您的代码,本来都很顺利今天突然不行了 macaca,可以加您 QQ 吗

—— 来自 TesterHome 官方 安卓客户端

Bach 回复

是什么原因?我这里也图片也显示不出来,请指点一下

kuier 回复

请问在 CMD 中单独运行 Macaca 有报错吗?QQ:752298505

jack 回复

如果你说的测试报告里面类似于我文中那种 screenshot 列中图片显示都是那个配图图标的话,需要点击这个图标跳转才能看到。如果点击了图标跳转后仍看不到的话,这个就需要具体问题具体分析了

王华林 回复

你好,我在 mac 上运行的时候也出现了这个情况,
请问一下 RunCases 文件里面的路径要怎么修改,因为才用 mac,所以麻烦一下您了。

王华林 回复

发现问题了,我是希望在缩略图上能直接看到截图,你提供的代码,写死了一个无效的缩略图,我把图片地址改成截图地址就可以了

Bach 回复

不好意思,我目前只在 win 上使用过,与其他系统有关的路径相关的(Public/RunCases),以及系统命令相关的(Public/Ports)你自己想想办法解决吧,相信你能行的

你好,我的 TestCase 中有多个的 test_.py.通过 run_cases.bat 执行测试,只有一个 test。py 被执行?该如何设置能执行多个的 test.py

summe 回复

没有需要配置的地方。运行 “TestSuite_xxx” 文件加下的 run_cases.bat 就会执行 “TestSuite_xxx” 文件夹下 “TestCase” 文件夹中的 test_xxx.py 里面的用例,你确定没重名什么的?你可以截图来看一下

我用的 mac 电脑,然后把相应的日志生成路径改了之后,运行你的 demo,发现在 MacacaServer.py 文件中报错:

wait macaca server all ready...
wait macaca server all ready...
macaca server all ready
Traceback (most recent call last):
File "run_all_cases.py", line 13, in
Drivers().run(cases)
File "../Public/Drivers.py", line 78, in run
macaca_server.start_server()
File "../Public/MacacaServer.py", line 47, in start_server
with open(file, 'r') as f:
IOError: [Errno 2] No such file or directory: '/Users/bita/Downloads/macacatest-master/TestReport/2017-07-11_11_47_53-4LWCAY9T99999999/macaca_server_port_3456.log'

实际上我看到生成的路径/Users/bita/Downloads/macacatest-master/TestReport/2017-07-11_11_47_53-4LWCAY9T99999999/直到这个目录都能正常生成,但是 macaca_server_port_3456.log 这个文件在相应的路径下没有,我是不是还有哪个地方没改对?

另外,我在 macaca server --verbose 中看到的数据

responseHandler.js:11:12 [master] pid:2002 Recieve HTTP Request from Client[2017-07-11 11:48:08]: method: GET url: /wd/hub/status, jsonBody: {}
responseHandler.js:47:14 [master] pid:2002 Send HTTP Respone to Client[2017-07-11 11:48:08]: {"sessionId":"","status":0,"value":"{\"build\":{},\"os\":{\"arch\":\"x64\",\"name\":\"darwin\",\"version\":\"\"}}"}

jsonBody 这块的值都为空,正常我们运行单个用例时 Recieve HTTP Request from Client,不都是 Post 方法吗?但是你这个运行的是 get 方法,我不确认是不是 get 方法的原因导致 jsonbody 值取不到?

66楼 已删除

@fengytn 你这个问题解决了吗??mac 也没有报告

赞!

不知有没有类似这种文章 nodejs 版的?

71楼 已删除

@hualin 你好 macaca 的 android toast 消息识别 你弄过吗?

老马 回复

不好意思,没使用过。你可以找找,macaca 应该是提供了对应方法的

74楼 已删除
linpengcheng 基于 ATX-Server 的 UI 自动化测试框架 中提及了此贴 06月18日 21:12
花开 ATX UI 自动化学习-偏 python 语法知识 中提及了此贴 10月22日 00:51
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册