arkcompiler_toolchain/test/autotest
swx1282997 6457c85152 Test case supplement
Test case supplement for debug singal instance

Issue:https://gitee.com/openharmony/arkcompiler_toolchain/issues/IAXKUS

Signed-off-by: swx1282997 <shiminnan@huawei.com>
2024-11-04 15:09:50 +08:00
..
aw Add automated testcase 2024-10-31 11:44:11 +08:00
resource Add automated testcase 2024-10-31 11:44:11 +08:00
scenario_test Test case supplement 2024-11-04 15:09:50 +08:00
pytest.ini Auto test: Hot reload test case 2024-10-22 16:53:10 +08:00
README.md Add auto testcase 2024-09-07 19:58:00 +08:00
requirements.txt Auto test: auto test framework 2024-08-22 19:55:23 +08:00
run.py Auto test framework evolution 2024-10-14 15:55:57 +08:00

调试调优自动化测试框架使用指南

[TOC]

1 框架设计

调试调优的通用流程可抽象为如下步骤:

  • IDE将应用推入设备并拉起应用或attach到已启动应用上

  • IDE与应用建立websocket连接

  • IDE与应用之间通过websocket发送和接受调试调优相关的业务消息消息格式遵循CDP协议

该自动化框架依据以上流程实现了应用启动、websocket连接、消息交互等步骤的自动化基于此可以进行调试调优用例的执行与开发

框架的目录结构与功能描述如下:

aw

封装了自动化框架通用的Action Words包括

  • application.py:应用启动、停止、安装、卸载等相关接口
  • fport.py执行hdc fport命令的相关接口指定端口号、进程ID和线程ID等用于后续的websocket连接
  • utils.py:封装各种通用的工具类接口
  • websocket.pywebsocket连接的关键基础类功能包括
    • connect server和debugger server的websocket连接
    • 采用消息队列实现websocket的消息发送与接收
    • 支持多实例应用的实现connect server的消息接收队列持续监听addInstance消息一旦接收到新的instance后便会创建对应的debugger server连接
    • 异步实现多条websocket连接的消息接收与发送通道均实现为协程可被提交到taskpool中作为异步任务执行
  • taskpool.py:异步任务池,功能包括:
    • 采用队列实现任务池的生命周期控制
    • 可在任意时刻提交任务到taskpool中进行异步执行
    • 可为每个任务添加任意多个回调函数,在任务结束后执行
  • cdpcdp协议的封装

scenario_test

场景测试用例目录

  • conftest.py基于pytest fixture实现的测试套方法
  • test_name_number.py:测试用例文件

resource

用于放置编译后的应用hap包

目录下的archive.json记录了应用工程名、hap包名和bundle name的对应关系

pytest.ini

python pytest库的配置文件

run.py

批量执行测试用例的入口文件

requirements.txt

自动化测试框架的python库依赖

2 测试用例执行

准备工作

  • 操作系统为Windows

  • 已安装hdc.exe并配置好环境变量可通过cmd启动执行

  • 测试设备已连接且开启USB调试

  • 下载自动化测试项目

    代码仓:https://gitee.com/openharmony/arkcompiler_toolchain

    项目目录:.\arkcompiler_toolchain\test\autotest

  • Python已安装且版本 >= 3.8.0

  • 安装Python依赖

    > cd .\arkcompiler_toolchain\test\autotest
    > python -m pip install -r requirements.txt [--trusted-host hostname -i Python_Package_Index]
    
  • 下载hap包

    通过归档链接下载hap包并将所有hap包移动到.\arkcompiler_toolchain\test\autotest\resource目录下

执行用例

cmd进入.\arkcompiler_toolchain\test\autotest目录,执行:

> python .\run.py

用例执行过程中cmd会实时输出用例日志信息执行完成后cmd会展示执行结果同时会生成测试报告并导出hilog日志

  • .\arkcompiler_toolchain\test\autotest\report\report.html:测试报告

  • .\arkcompiler_toolchain\test\autotest\report\xxx.hilog.txt每个测试用例对应一份debug级别的hilog日志

  • .\arkcompiler_toolchain\test\autotest\report\faultlogger:用例执行过程中产生的错误日志

3 测试用例开发

测试应用

根据测试用例场景确定并开发你的测试应用编译后将应用hap包放在.\arkcompiler_toolchain\test\autotest\resource目录下

测试套

测试套以pytest fixture形式开发对应于.\arkcompiler_toolchain\test\autotest\scenario_test\conftest.py中的一个方法;

对于一个确定的测试应用和一套固定的配置信息我们可以将他们抽象出来作为一个fixture基于该fixture我们可以开发多个测试用例

fixture写法举例如下

@pytest.fixture(scope='class')		# 该装饰器指定下面的函数是一个fixture
def test_suite_debug_01():			# fixture名称
    logging.info('running test_suite_debug_01')
	
    bundle_name = 'com.example.worker'
    hap_name = 'MyApplicationWorker.hap'

    config = {'connect_server_port': 15678,
              'debugger_server_port': 15679,
              'bundle_name': bundle_name,
              'hap_path': rf'{os.path.dirname(__file__)}\..\resource\{hap_name}'}
	
     # 将应用推入设备,并以-D模式启动
    pid = Application.launch_application(config['bundle_name'], config['hap_path'], start_mode='-D')
    assert pid != 0, logging.error(f'Pid of {hap_name} is 0!')
    config['pid'] = pid
	
    # hdc fport
    Fport.clear_fport()
    Fport.fport_connect_server(config['connect_server_port'], config['pid'], config['bundle_name'])
	
    # 实例化WebSocket对象
    config['websocket'] = WebSocket(config['connect_server_port'], config['debugger_server_port'])
	
    # 实例化TaskPool对象
    config['taskpool'] = TaskPool()

    return config

样例参考:.\arkcompiler_toolchain\test\autotest\scenario_test\conftest.py => test_suite_debug_01

测试用例

测试用例放置在.\arkcompiler_toolchain\test\autotest\scenario_test\目录下,每个.py文件对应一个测试用例命名规则为test\_测试项\_编号.py

测试用例代码文件结构如下:

@pytest.mark.debug
@pytest.mark.timeout(40)
class TestDebug01:
    def setup_method(self):
        pass
    
    def teardown_method(self):
        pass
    
    def test(self, test_suite_debug_01):
        pass
    
    async def procedure(self, websocket):
        pass

  • 装饰器@pytest.mark.debug标明该用例是一个测试debug功能的用例debug可以改为其它任意名字如cpu_profiler

  • 装饰器@pytest.mark.timeout(40)标明该用例必须在40s内执行完毕否则不通过

  • class TestDebug01 是该测试用例对应的测试类,测试类必须以Test开头

  • setup_class 方法在用例开始执行前被执行,其中放置一些需要初始化的内容

  • teardown_clas 方法在用例结束执行后被执行,其中放置一些需要结束或清理的内容

  • test 方法是测试用例执行的入口,注意以下几点:

    • 第二个参数为fixture不仅可以标识该用例属于哪个测试套还可以获取该fixture执行后的返回结果在test方法被执行前fixture会首先被执行

    • 通过下面的代码将websocket中封装的main task提交到taskpool等待所有任务结束并捕获异常

      taskpool.submit(websocket.main_task(taskpool, websocket, self.procedure, pid))
      taskpool.await_taskpool()
      taskpool.task_join()
      if taskpool.task_exception:
          raise taskpool.task_exception
      
  • procedure方法测试步骤和预期结果执行的位置在test方法中procedure作为参数被提交到taskpool中因此其同样作为一个异步任务在执行

当我们新增一个测试用例时主要工作就是在procedure方法中放置我们的测试步骤和预期结果。首先我们可以手动执行一次测试用例并抓出connect server、debugger server交互的日志信息。此后我们可以对照日志信息在procedure方法中添加内容每一次消息发送可以当作一个测试步骤每一次消息接收可以当作一次预期结果

例如:

################################################################################################################
# main thread: Debugger.getPossibleAndSetBreakpointByUrl
################################################################################################################
id = next(self.id_generator)	# 获取此次发送消息的id

# 构造断点信息
locations = [debugger.BreakLocationUrl(url='entry|entry|1.0.0|src/main/ets/pages/Index.ts', line_number=22),
             debugger.BreakLocationUrl(url='entry|entry|1.0.0|src/main/ets/pages/Index.ts', line_number=26)]

# 发送消息并获取返回值调用cdp库中的debugger.get_possible_and_set_breakpoint_by_url(locations)可以自动拼接cdp消息
response = await communicate_with_debugger_server(main_thread_instance_id,
                                                  main_thread_to_send_queue,
                                                  main_thread_received_queue,
                                                  debugger.get_possible_and_set_breakpoint_by_url(locations),
                                                  id)

# 判断返回结果是否符合预期
response = json.loads(response)
assert response['id'] == id
assert response['result']['locations'][0]['id'] == 'id:22:0:entry|entry|1.0.0|src/main/ets/pages/Index.ts'
assert response['result']['locations'][1]['id'] == 'id:26:0:entry|entry|1.0.0|src/main/ets/pages/Index.ts'

注意:

  • 建议在测试类声明后,用类注释写明该测试用例的内容;
  • 每个测试步骤和预期结果之间,用上述注释方式隔开,并标明此次测试步骤的操作;
  • 对于aw中未实现的CDP协议请封装在aw/cdp目录下对应的domain文件中

样例参考:.\arkcompiler_toolchain\test\autotest\scenario_test\test_debug_01.py