游戏测试 —— 战斗内核的自动化测试

1077 篇文章 11 订阅
682 篇文章 3 订阅

今天给大家分享一个游戏自动化测试的落地。这款游戏有独立的战斗内核负责局内战斗的计算,所以每次需要测试战斗内核时,都需要服务器重新部署,客户端(移动端、PC端等)重新出包,最后才能交付给测试进行测试,整个流程比较长,也比较耗时,所以我们就考虑在战斗内核更新时就进行测试,这样可以简化测试流程,节约时间。

经过和内核组开发的探讨后,决定使用内核开发组提供的QT工具(如下图展示),在本地运行游戏的战斗内核,通过执行多个命令构建起测试的场景,再通过数据交互拿到测试数据,以此来达到我们想要的测试目的。

1. 环境准备

  • Windows10

  • Python3.7

  • Allure

  • Python第三方库:pytest、allure-pytest、python-gitlab、zipp、xlrd

2. 实现流程

2.1 通讯方式

启动QT时,启动参数中包含通讯的端口号。QT启动之后,使用python与QT在本地建立socket连接进行通讯。

    def __init__(self, port):
        self.port = port
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.data = {}

    def connect(self):
        """
        建立连接
        """
        localhost = socket.gethostbyname(socket.gethostname())
        self.sock.connect({localhost, self.port})
复制代码

将每条用例的操作命令存放在列表中,遍历列表进行命令的发送,每条命令json序列化之后,通过socket连接进行发送,发送完成后,对发送的命令进行判断,再做出下一步的操作。

    def send(self, data):
        """
        发送命令
        """
        for d in data:
            if 'sleep' == d.keys():
                # 保持socket连接,向QT发送心跳数据
                self.hearbeats(int(d['sleep'][0]), int(d['sleep'][1]))
            else:
                _ = json.dumps(d).encode(encoding='utf-8')
                self.sock.send(_)
                # 多条命令发送需要间隔0.3s
                time.sleep(0.3)
                # 发送初始化命令之后,等待QT数据初始化
                if d['Pack-Field'] == 'client.initserver':
                    time.sleep(5)
                # 当Hread-Field==2时表示向内核请求当前游戏数据
                if d['Hread-Field'] == '2':
                    # 8个玩家数据+1个游戏场景数据
                    self.data = [self.recv_game_data() for _ in range(9)]
复制代码

接收数据时,前8个字节为包的大小,后面则为我们需要的数据,因为是在本地进行的测试,所以没有对数据进行加密,接收到的数据可以直接转成json格式,在接收数据时会收到QT发过来的心跳数据,将心跳数据去除掉之后,就是我们想要的游戏数据了。

    def recv_game_data(self):
        """
        接收游戏数据,去除心跳数据
        """
        data = self.recv_data()
        # 当Hread-Field==Heartbeat时表示数据为心跳数据
        while data['Hread-Field'] == 'Heartbeat':
            data = self.recv_data()
        else:
            return data

    def recv_data(self):
        size = struct.unpack('q', self.recv(8))[0]
        data = json.loads(self.recv(size).decode('utf-8'))
        return data

    def recv(self, size):
        n = 0
        data = b''
        while n < size:
            _ = self.sock.recv(size - n)
            data += _
            n += len(_)
复制代码

2.2 用例设计

将用例统一存放在Excel文件中,每个Sheet为一个游戏模式,每张表都包含了用例编号、描述、状态、步骤、数据校验。用例执行时,按照预先设计好的步骤向QT发送命令构建测试场景,接收到QT返回的数据之后,再与数据校验中的数据进行比对,以此来校验内核功能的正确性。

用例编号用例描述用例状态测试步骤数据校验
基础金币-001对局获胜,胜利金币+1,基础金币+5执行client.initserver,
client.setRound.4.0,
2,
client.addChessToMap.0.110011.0.0,
client.goNextStage,
sleep.4.5,
2
{"data_2":{"player_0":{"gold_increase":6},"GameMode":0}}

2.3 数据校验

QT每次返回的数据中都包含了8个玩家数据以及1个游戏场景数据,所以我们按照用例中声明的校验字段,提取返回数据中相对应的字段进行对比校验,具体的实现代码如下:

    def format_data(self):
        """
        格式化接收到的数据
        """
        for _ in self.received_data.keys():
            data = self.received_data[_]
            self.received_data_formatted[_] = dict()
            for player_num in range(len(data)):
                player_data = data[player_num]
                if player_num == 8:
                    self.received_data_formatted.get(_)['game_scene'] = player_data
                else:
                    self.received_data_formatted.get(_)[f'player_{player_num}'] = player_data
    
    def verify_data(self):
        """
        进行数据校验
        """
        self.format_data()
        for data_key in self.assert_data.keys():
            self.data_key = data_key
            for check_type_1 in self.assert_data[data_key].keys():
                self.check_type = check_type_1
                if check_type_1 == 'GameMode':
                    try:
                        self.GameMode(data_key)
                    except AssertionError as e:
                        self.failed_dict['GameMode'] = e.args
                else:
                    for check_type_2 in self.assert_data[data_key][check_type_1]:
                        try:
                            # 执行对应的校验模块
                            eval(f'self.{check_type_2}()')
                        except AssertionError as e:
                            # 捕获校验模块返回的异常并记录
                            self.failed_dict[check_type_2] = e.args
复制代码

数据校验中的字段如gold_increase、GameMode都对应一个校验的模块,gold_increase指玩家当前金币的增加数量,GameMode指当前的游戏模式,当然还有很多校验模块如:HandleChess、HandleEquip、ChessBoard、BoardEquip...等等

    def gold_increase(self):
        # 校验金币增加值
        assert_data = self.assert_data[self.data_key][self.check_type]['gold_increase']
        received_data_1 = self.received_data_formatted[f'data_{int(self.data_key[-1:]) - 1}'][self.check_type]['Pack-Field']['k_19']
        received_data_2 = self.received_data_formatted[self.data_key][self.check_type]['Pack-Field']['k_19']
        increase_num = received_data_2-received_data_1
        if increase_num != int(assert_data):
            raise AssertionError(f'{self.data_key}-{self.check_type}: {increase_num} != {assert_data}')
    
    def GameMode(self, data_key):
    # 校验当前游戏模式
    game_mode_assert = self.assert_data[data_key]['GameMode']
    game_mode_received = self.received_data_formatted.get(data_key)['game_scene']['Pack-Field']['k_0']
    assert game_mode_received == game_mode_assert,\
        f'{self.data_key}-{self.check_type}: {game_mode_received} != {game_mode_assert}'
复制代码

2.4 内核版本的更新

使用python-gitlab库下载gitlab上指定内核分支中的文件,下载完成后替换掉旧的文件即可,以此来更新本地的内核版本,安装python-gitlab库。

pip install python-gitlab
复制代码
import gitlab
import os
import time
curPath = os.path.abspath(os.path.dirname(__file__))
rootPath = os.path.split(curPath)[0]

class DownloadFiles:
    """
    从gitlab上下载指定分支文件
    """
    def __init__(self, version):
        self.dir_name = None
        self.version = version

    def create_dir(self):
        if not os.path.isdir(self.dir_name):
            os.makedirs(self.dir_name)
            time.sleep(0.1)

    def start_get(self):
        gl = gitlab.Gitlab.from_config('xiaoming', [f'{curPath}/git.ini'])
        gl.projects.list()
        project = gl.projects.get(1234) # 项目ID
        root_path = f'{rootPath}/resource/'
        info = project.repository_tree(all=True, recursive=True, as_list=True, ref=self.version)
        file_list = list()
        if not os.path.isdir(root_path):
            os.makedirs(root_path)
        os.chdir(root_path)
        for info_dir in range(len(info)):
            if info[info_dir]['type'] == 'tree':
                self.dir_name = info[info_dir]['path']
                self.create_dir()
            else:
                file_name = info[info_dir]['path']
                # logger.info(file_name)
                if file_name == 'windows.zip':
                    file_list.append(file_name)
                if 'Datas_jit' in file_name:
                    file_list.append(file_name)
        if 'Datas_jit/' not in str(file_list):
            # raise ValueError("未检测到Datas相关文件,请上传")
            pass
        for info_file in range(len(file_list)):
            get_file = project.files.get(file_path=file_list[info_file], ref=self.version)
            content = get_file.decode()
            with open(file_list[info_file], 'wb') as code:
                logger.info(f"START-DOWNLOAD: {file_list[info_file]}")
                code.write(content)
        logger.info(f"DOWNLOAD COMPLETE!")
复制代码

3. 不足之处

当前内核自动化测试还存在着一些不足之处:

  • 用例的编写比较复杂,首先需要熟悉命令,其次是校验的字段名,对数据校验的格式也有要求;

  • 当前版本只能在Windows环境中运行,如果可以直接在测试服上运行是最好的;

  • 如果C++的代码有改动的话,就需要手动更新QT;

如果你还发现了其他的问题,欢迎在评论区指出,也希望可以和对游戏自动化测试感兴趣的朋友一起交流游戏自动化测试相关的方法和经验。


END绵薄之力

最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!

软件测试面试小程序

被百万人刷爆的软件测试题库!!!谁用谁知道!!!全网最全面试刷题小程序,手机就可以刷题,地铁上公交上,卷起来!

涵盖以下这些面试题板块:

1、软件测试基础理论 ,2、web,app,接口功能测试 ,3、网络 ,4、数据库 ,5、linux

6、web,app,接口自动化 ,7、性能测试 ,8、编程基础,9、hr面试题 ,10、开放性测试题,11、安全测试,12、计算机基础

获取方式 :

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: rootkits——windows内核的安全防护是一本针对Windows操作系统的内核级别安全防护的PDF文档。这本文档主要涵盖了rootkits的定义、特征、工作原理、攻击方式以及防御方法等内容。 首先,rootkits是一种恶意软件,通过植入操作系统内核来隐藏自身并实施攻击。文档详细介绍了rootkits的特征,例如可以修改系统内核代码、隐藏进程和文件等,从而使其在操作系统中隐蔽存在。 文档还解释了rootkits的工作原理,即通过劫持系统调用、Hook函数和修改系统数据结构等方式来实现恶意行为。同时,文档还介绍了rootkits使用的主要攻击方式,如键盘记录、远程控制、网络欺骗等。 为了帮助用户保护自己的系统免受rootkits的攻击,该文档提供了一些防御方法。例如,通过实时监控系统进程、文件和注册表的变化,及时检测和阻止rootkits的安装和运行;使用可信任的安全软件进行系统扫描和漏洞修复;定期更新操作系统和应用程序的安全补丁等。 此外,文档还提供了一些用于检测和清除rootkits的工具和技术,如反rootkit软件、恶意代码扫描器等。这些工具可以帮助用户及时发现和清除系统中已经存在的rootkits。 总的来说,rootkits——windows内核的安全防护这本PDF文档详细介绍了rootkits的定义、工作原理、攻击方式以及防御方法。对于那些希望了解和加强Windows系统安全性的用户来说,这本文档是一份宝贵的参考资料。 ### 回答2: rootkits是一种恶意软件,能够隐藏在操作系统内核中,并且在被感染的计算机上实施恶意活动。它们可以完全控制系统,并且能够绕过传统的安全防护措施。为了确保计算机系统的安全,Windows内核的安全防护PDF提供了一种防范rootkits的方法。 首先,PDF文件详细介绍了rootkits的工作原理和其入侵系统的方式。这使得用户能够了解到rootkits的特征以及它们可能对计算机造成的危害。了解敌人才能更好地进行防范。 其次,PDF文件提供了关于如何检测和清除rootkits的指南。通过使用一些专业的工具和技术,用户可以发现并清除被rootkits感染的系统。这些工具可以扫描内核并查找任何异常行为,以及寻找rootkits常用的隐藏技术。通过及时发现和清除rootkits,可以最大限度地保护系统免受恶意活动的威胁。 此外,PDF文件还提供了一些加强系统安全的建议。比如,更新操作系统和应用程序,使用强密码保护帐户和网络连接,以及限制对敏感文件和设置的访问权限等等。这些措施可以帮助用户防止rootkits和其他恶意软件的入侵。 最后,PDF文件还介绍了一些未来的趋势和建议,以进一步提高Windows内核的安全性。这些建议包括加强内核的隔离性,采用虚拟化技术进行保护,以及实施更严格的访问控制等。这些措施将有助于加强系统的安全性,并提高对rootkits的抵御能力。 总的来说,Windows内核的安全防护PDF是一份有价值的文档,提供了对抗rootkits的指南和建议。通过采取相应的措施,用户可以保护系统免受rootkits的威胁,并提高整体的安全性。 ### 回答3: rootkits是一种针对Windows操作系统的恶意软件,它们通过在操作系统内核中植入恶意代码,可以隐藏自身的存在并在系统启动时加载运行。rootkits通过修改关键的系统文件、进程和注册表项等方式,使恶意软件难以被发现和清除。 《rootkits——windows内核的安全防护》这本PDF书籍探讨了如何保护Windows内核免受rootkits的攻击。书中首先介绍了rootkits的原理和工作方式,包括rootkits的分类、入侵方式和隐藏技术等。然后,书中深入讲解了一些重要的内核安全技术,如代码签名、驱动程序的安全性和安全的加载和验证过程等。书中还提供了一些常见的rootkits检测和清除工具,以帮助用户发现和清除系统中的恶意软件。 此外,书中还介绍了一些预防rootkits攻击的措施和最佳实践。例如,强化系统安全性、定期更新操作系统和安全软件、限制管理员权限、使用防火墙和入侵检测系统等。这些措施可以有效减少系统被rootkits攻击的风险。 总之,《rootkits——windows内核的安全防护》这本PDF书籍全面讲解了如何保护Windows内核免受rootkits攻击的方法和技术。它可以帮助用户了解rootkits的工作原理,并提供了一些重要的内核安全技术和预防措施,以增强系统的安全性和防御能力。对于IT安全从业人员和对计算机安全感兴趣的人来说,这本书是一本不可或缺的参考资料。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值