这里有一些在写测试用例时可能用得上的方法和技巧。

# 1、选择节点的方法

开发者可以通过几种不同的方法来指定需要操作的节点。

# 通过节点的 Path 值来指定节点

Path的格式为:

{节点的className[节点属性=目标值|.......]}>或者.{节点的className[节点属性=目标值|.......]}.....

Path中节点由 {} 包围,className作为节点的名称,后方 [] 中包括节点的额外选择条件。额外选择条件可不填写,条件格式为 k=v ,多个条件之间用 | 连接,例如:

{a[k1=v1|k2=v2]}

表示该 Path 会选择className=a,同时满足属性k1=v1以及k2=v2的节点。

多个节点之间支持由 . 或者 > 连接,它们分别表示:

  1. . 为选择当前节点的后代节点,即当前节点的所有后代节点都会作为备选。

  2. > 为仅选择当前节点的子节点。

例如:

  {a}.{b}>{c}

Path可以调用 findPath 方法传入调用,获取对应的 NodeSelector 实例对象。CaseContext实例对象或者 NodeSelector 实例对象都可以调用 findPath 方法,返回值为 NodeSelector 实例对象,如:

tmp = await c.findPath("{a}.{b}>{c}") //JavaScript
tmp = c.find_path("{a}.{b}>{c}") #Python

# 通过链式调用来指定节点

如果不想使用 Path 选择节点,还可以使用链式调用的方式:

tmp = await c.select((n)=>{ return (n["a"] || "") === "b" }).child({"c" : "d"}) //JavaScript
tmp = c.select(lambda n: n.get("a",None) == "b").child({"c" : "d"}) #Python

注意,JavaScript版本中 CaseContext实例对象的 findPath 方法以及select、child方法都是async function,调用时需要通过await 获取结果

# 通过图像识别来指定节点

测试框架提供图像识别的API,可以根据对目标图片的识别结果来获取其位置并进行交互。

  • JavaScript版本调用方式:
let imgPath = path.join("img","1.png") //为了兼容跨平台,请使用系统库生成相对路径
tmp = await c.findImg(imgPath)
  • Python版本调用方式:
img_path = os.path.join("img","1.png") #为了兼容跨平台,请使用系统库生成相对路径
tmp = c.find_img(img_path)

目标图片的路径,是基于测试 Case 路径的。如果目标图片的绝对路径为 ~/{workspace}/img/1.png的话,则 findImg 传入的 imgPath 则为img/1.png。

findImg函数返回的是 ImgSelector 实例对象,可以使用该对象对目标图片位置进行操作。

Tips

  • 传入的 imgPath 由于跨平台原因,最好使用 path.join 方式进行连接。
  • 图片识别的准确性可能会存在一定误差,如有问题请反馈给我们,谢谢。

# 2、操作节点的方法

测试框架目前支持点击、滑动等操作。通过调用 ImgSelector 实例对象以及 NodeSelector 实例对象的 tap 或者 swipe 方法,触发对应操作。每次操作之后,建议考虑游戏具体场景适当等待。 如果搜索节点时,未找到目标节点,则返回的 ImgSelector 实例对象或 NodeSelector 实例对象内容为空,这时触发事件会产生error。建议如果无法确定是否能获取到节点的时候,通过isEmpty()判断是否为空。 如果满足条件的节点有多个,则 NodeSelector 实例对象也会包括多个节点对象。这时触发事件,则会产生error。如果出现这种问题,建议调整选择条件。

# 3、完整的 Case 示例

  • JavaScript版本:
const mini_game_test = require("mini_game_test")
const BaseCase = mini_game_test.BaseCase
const logger = mini_game_test.logger

class Test extends BaseCase {
    async run(c) {
        logger.info("start")

        let tmp = null
        //获取节点
        tmp = await c.findPath("{laya.display.Stage[nodeType=laya.display.Stage|covered=false]}>{laya.display.Sprite[index=0|nodeType=laya.display.Sprite|covered=false]}>{laya.display.Sprite[index=2|nodeType=laya.display.Sprite]}>{laya.display.Sprite[index=2|nodeType=laya.display.Sprite|covered=false]}")
        //点击
        await tmp.tap()
        //等待
        await c.sleep(3000)
        let endStatus = false
        for (let i = 0; i < 10; i++) {
            await c.tap(0.5, 0.5)
            await c.sleep(2000)
            tmp = await c.findPath("{laya.display.Stage[nodeType=laya.display.Stage|covered=false]}>{laya.display.Sprite[index=0|nodeType=laya.display.Sprite|covered=false]}>{laya.display.Sprite[index=5|nodeType=laya.display.Sprite|covered=false]}>{laya.display.Sprite[index=3|nodeType=laya.display.Sprite|covered=false]}")
            if (!tmp.isEmpty()) {
                logger.info("game end")
                endStatus = true
                break
            }
        }

        if (!endStatus) {
            logger.info("game not end or game error")
            return
        }

        tmp = await c.findPath("{laya.display.Stage[nodeType=laya.display.Stage|covered=false]}>{laya.display.Sprite[index=0|nodeType=laya.display.Sprite|covered=false]}>{laya.display.Sprite[index=5|nodeType=laya.display.Sprite|covered=false]}>{laya.display.Sprite[index=3|nodeType=laya.display.Sprite|covered=false]}")
        await tmp.tap()
        await c.sleep(3000)
        tmp = await c.findPath("{laya.display.Stage[nodeType=laya.display.Stage|covered=false]}>{laya.display.Sprite[index=0|nodeType=laya.display.Sprite|covered=false]}>{laya.display.Sprite[index=6|nodeType=laya.display.Sprite|covered=false]}>{laya.display.Sprite[index=0|nodeType=laya.display.Sprite|covered=false]}")
        await tmp.tap()
        await c.sleep(3000)
        tmp = await c.findPath("{laya.display.Stage[nodeType=laya.display.Stage|covered=false]}>{laya.display.Sprite[index=0|nodeType=laya.display.Sprite|covered=false]}>{laya.display.Sprite[index=5|nodeType=laya.display.Sprite|covered=false]}>{laya.display.Sprite[index=4|nodeType=laya.display.Sprite|covered=false]}")
        await tmp.tap()
        await c.sleep(3000)
        tmp = await c.findPath("{laya.display.Stage[nodeType=laya.display.Stage|covered=false]}>{laya.display.Sprite[index=0|nodeType=laya.display.Sprite|covered=false]}>{laya.display.Sprite[nodeType=laya.display.Sprite|covered=false]}>{laya.display.Sprite[index=7|nodeType=laya.display.Sprite|covered=false]}")
        await tmp.tap()
        await c.sleep(3000)
    }
}

logger.debug("start")

const t = new Test()
t.start()
  • Python版本:
# -*- coding: utf-8 -*-
from mini_game_test_case_py.case.BaseCase import BaseCase
from mini_game_test_case_py.lib import config
from mini_game_test_case_py.lib import Asserts
from mini_game_test_case_py.lib import Logger
import time

class TestCase(BaseCase):
    def run(self, c):
        Logger.info("start case")
        #获取开始按钮
        start_node = c.find_path(
            "{laya.display.Stage[covered=false]}>{laya.display.Sprite[index=0|covered=false]}>{laya.display.Sprite}>{laya.display.Sprite[index=2|covered=false]}")
        #判断开始按钮是否存在
        Asserts.assert_nodeselector_exists(start_node)
        #点击
        start_node.tap()
        c.sleep(6000)

        start_time = time.time()
        
        endStatus = False
		
        #循环判断paihang_node是否出现
        while time.time() - start_time < 30  :
            c.tap(0.5, 0.5, is_per=True)
            time.sleep(1)
            paihang_node = c.find_path("{laya.display.Stage[covered=false]}>{laya.display.Sprite[index=0|covered=false]}>{laya.display.Sprite[index=5|covered=false]}>{laya.display.Sprite[index=3|covered=false]}")
            if not paihang_node.is_empty():
                Logger.info("game end")
                endStatus = True
                break

        if not endStatus:
            Logger.info("game end error")
            return
        
        tmp = c.find_path("{laya.display.Stage[covered=false]}>{laya.display.Sprite[index=0|covered=false]}>{laya.display.Sprite[index=5|covered=false]}>{laya.display.Sprite[index=3|covered=false]}")
        Asserts.assert_nodeselector_exists(tmp)
        tmp.tap()
        c.sleep(6000)
        tmp = c.find_path("{laya.display.Stage[covered=false]}>{laya.display.Sprite[index=0|covered=false]}>{laya.display.Sprite[index=6|covered=false]}>{laya.display.Sprite[index=0|covered=false]}")
        Asserts.assert_nodeselector_exists(tmp)
        tmp.tap()
        c.sleep(6000)
        tmp = c.find_path("{laya.display.Stage[covered=false]}>{laya.display.Sprite[index=0|covered=false]}>{laya.display.Sprite[index=5|covered=false]}>{laya.display.Sprite[index=4|covered=false]}")
        Asserts.assert_nodeselector_exists(tmp)
        tmp.tap()
        c.sleep(6000)
        tmp = c.find_path("{laya.display.Stage[covered=false]}>{laya.display.Sprite[index=0|covered=false]}>{laya.display.Sprite[covered=false]}>{laya.display.Sprite[index=7|covered=false]}")
        Asserts.assert_nodeselector_exists(tmp)
        tmp.tap()
        c.sleep(6000)        
        Logger.info("end test")

t = TestCase()
t.start()