哔哩哔哩-API收集整理:接口文档自动化测试方案

哔哩哔哩-API收集整理:接口文档自动化测试方案

你是否还在为B站API接口的频繁变更而头疼?是否因手动测试耗时费力而影响开发效率?本文将基于bilibili-API-collect项目,提供一套完整的接口文档自动化测试方案,帮助你轻松应对API测试挑战。读完本文,你将掌握API签名验证、自动化测试脚本编写、错误处理与报告生成等核心技能,让API测试效率提升80%。

项目概述

bilibili-API-collect是一个致力于收集整理哔哩哔哩(B站)各类非官方API的开源项目。该项目采用黑箱法、控制变量法、代码逆向分析等多种研究方法,对B站Web、APP、TV等客户端的野生API进行系统性梳理,为开发者提供了宝贵的API调用参考。

项目logo

项目主要包含REST API和gRPC两种接口类型,接口请求数据大多为url query表单或JSON,返回数据大多为JSON或Protobuf,且强制使用HTTPS协议。完整的文档结构可参考项目README

API签名机制解析

B站API采用多种签名机制进行接口鉴权,主要包括APP签名和WBI签名两种方式。

APP签名

APP签名主要用于客户端API接口,其核心步骤如下:

  1. 在参数中添加appkey字段
  2. 按照参数Key进行排序
  3. 对排序后的参数进行url query序列化,并拼接对应的appsec进行MD5哈希运算
  4. 将计算得到的哈希值作为sign字段添加到参数中
import hashlib
import urllib.parse

def appsign(params, appkey, appsec):
    '为请求参数进行 APP 签名'
    params.update({'appkey': appkey})
    params = dict(sorted(params.items())) # 按照 key 重排参数
    query = urllib.parse.urlencode(params) # 序列化参数
    sign = hashlib.md5((query+appsec).encode()).hexdigest() # 计算 api 签名
    params.update({'sign':sign})
    return params

详细实现可参考APP API签名文档,已知的APPKey列表可查阅APPKey文档

WBI签名

WBI签名是自2023年3月起在Web端部分接口采用的新签名方式,主要涉及w_ridwts两个字段。其签名流程相对复杂,主要包括:

  1. 获取实时口令img_keysub_key
  2. 打乱重排实时口令获得mixin_key
  3. 计算签名w_rid
  4. 向请求参数中添加w_ridwts字段
def getMixinKey(orig: str):
    '对 imgKey 和 subKey 进行字符顺序打乱编码'
    return reduce(lambda s, i: s + orig[i], mixinKeyEncTab, '')[:32]

def encWbi(params: dict, img_key: str, sub_key: str):
    '为请求参数进行 wbi 签名'
    mixin_key = getMixinKey(img_key + sub_key)
    curr_time = round(time.time())
    params['wts'] = curr_time                                   # 添加 wts 字段
    params = dict(sorted(params.items()))                       # 按照 key 重排参数
    # 过滤 value 中的 "!'()*" 字符
    params = {
        k : ''.join(filter(lambda chr: chr not in "!'()*", str(v)))
        for k, v 
        in params.items()
    }
    query = urllib.parse.urlencode(params)                      # 序列化参数
    wbi_sign = md5((query + mixin_key).encode()).hexdigest()    # 计算 w_rid
    params['w_rid'] = wbi_sign
    return params

完整的WBI签名实现可参考Wbi签名文档

自动化测试框架设计

测试框架架构

测试框架架构

自动化测试框架主要包含以下几个核心模块:

  • 用例管理模块:负责测试用例的定义、组织和管理
  • 请求处理模块:处理API请求的构建、发送和响应解析
  • 签名生成模块:实现APP签名和WBI签名等签名机制
  • 断言模块:提供丰富的断言方法验证接口响应
  • 报告生成模块:生成直观的测试报告
  • 配置模块:管理测试环境、接口地址等配置信息

核心实现代码

以下是一个基于Python的简单测试框架实现:

import requests
import json
import hashlib
import urllib.parse
import time
from functools import reduce

class BiliAPITester:
    def __init__(self, appkey=None, appsec=None):
        self.appkey = appkey
        self.appsec = appsec
        self.session = requests.Session()
        self.session.headers.update({
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3',
            'Referer': 'https://www.bilibili.com/'
        })
        self.mixinKeyEncTab = [
            46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49,
            33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40,
            61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57, 62, 11,
            36, 20, 34, 44, 52
        ]
        self.wbi_img_key = None
        self.wbi_sub_key = None

    def get_wbi_keys(self):
        """获取WBI签名所需的img_key和sub_key"""
        resp = self.session.get('https://api.bilibili.com/x/web-interface/nav')
        resp.raise_for_status()
        json_content = resp.json()
        img_url = json_content['data']['wbi_img']['img_url']
        sub_url = json_content['data']['wbi_img']['sub_url']
        self.wbi_img_key = img_url.rsplit('/', 1)[1].split('.')[0]
        self.wbi_sub_key = sub_url.rsplit('/', 1)[1].split('.')[0]
        return self.wbi_img_key, self.wbi_sub_key

    def app_sign(self, params):
        """对参数进行APP签名"""
        if not self.appkey or not self.appsec:
            raise ValueError("appkey和appsec必须提供")
        return appsign(params, self.appkey, self.appsec)

    def wbi_sign(self, params):
        """对参数进行WBI签名"""
        if not self.wbi_img_key or not self.wbi_sub_key:
            self.get_wbi_keys()
        return encWbi(params, self.wbi_img_key, self.wbi_sub_key)

    def test_api(self, url, params, sign_type='wbi', method='get', expected_code=0):
        """测试API接口"""
        if sign_type == 'app':
            signed_params = self.app_sign(params.copy())
        elif sign_type == 'wbi':
            signed_params = self.wbi_sign(params.copy())
        else:
            signed_params = params.copy()

        try:
            if method.lower() == 'get':
                resp = self.session.get(url, params=signed_params)
            else:
                resp = self.session.post(url, data=signed_params)
            
            resp.raise_for_status()
            result = resp.json()
            
            # 断言状态码
            assert result.get('code') == expected_code, f"API调用失败: {result.get('message')}"
            
            return {
                'success': True,
                'status_code': resp.status_code,
                'response': result,
                'params': signed_params
            }
        except Exception as e:
            return {
                'success': False,
                'error': str(e),
                'params': signed_params
            }

自动化测试用例设计

针对B站API的特点,我们可以从以下几个维度设计自动化测试用例:

接口功能测试

针对每个API接口,设计测试用例验证其基本功能是否正常,包括正常场景和异常场景。

例如,测试用户基本信息接口user/info.md

def test_user_info(tester):
    """测试用户信息接口"""
    # 正常场景
    params = {'mid': '1'}
    result = tester.test_api('https://api.bilibili.com/x/space/wbi/acc/info', params)
    assert result['success'], f"用户信息接口测试失败: {result.get('error')}"
    assert 'data' in result['response'], "响应中缺少data字段"
    assert result['response']['data']['mid'] == 1, "返回的用户ID不正确"
    
    # 异常场景 - 用户不存在
    params = {'mid': '999999999'}
    result = tester.test_api('https://api.bilibili.com/x/space/wbi/acc/info', params, expected_code=-404)
    assert result['success'], f"用户信息接口异常场景测试失败: {result.get('error')}"
    
    return "用户信息接口测试通过"

接口性能测试

针对核心API接口,设计性能测试用例,验证接口的响应时间、吞吐量等性能指标。

import time
import statistics

def test_api_performance(tester, url, params, sign_type='wbi', iterations=10):
    """测试API性能"""
    response_times = []
    
    for i in range(iterations):
        start_time = time.time()
        result = tester.test_api(url, params, sign_type)
        end_time = time.time()
        
        assert result['success'], f"API调用失败: {result.get('error')}"
        response_times.append(end_time - start_time)
    
    # 计算性能指标
    avg_time = statistics.mean(response_times)
    p90_time = statistics.quantiles(response_times, n=10)[8]
    max_time = max(response_times)
    min_time = min(response_times)
    
    return {
        'avg_time': avg_time,
        'p90_time': p90_time,
        'max_time': max_time,
        'min_time': min_time,
        'iterations': iterations
    }

接口兼容性测试

B站API存在多个版本和多种客户端类型,因此需要测试接口在不同版本、不同客户端类型下的兼容性。

def test_api_compatibility(tester, url, params, appkey_list):
    """测试API在不同appkey下的兼容性"""
    results = []
    
    for app_info in appkey_list:
        tester.appkey = app_info['appkey']
        tester.appsec = app_info['appsec']
        
        try:
            result = tester.test_api(url, params, sign_type='app')
            results.append({
                'appkey': app_info['appkey'],
                'app_type': app_info['app_type'],
                'success': True,
                'message': '测试通过'
            })
        except Exception as e:
            results.append({
                'appkey': app_info['appkey'],
                'app_type': app_info['app_type'],
                'success': False,
                'message': str(e)
            })
    
    return results

错误处理与常见问题

在API测试过程中,可能会遇到各种错误,熟悉常见的错误码可以帮助我们快速定位问题。

常见错误码

代码含义
-101账号未登录
-102账号被封停
-111csrf校验失败
-403访问权限不足
-404资源不存在
-500服务器错误
-503过载保护,服务暂不可用
-799请求过于频繁,请稍后再试

完整的错误码列表可参考公共错误码文档

常见问题解决方案

  1. 签名错误:检查签名算法实现是否正确,特别是参数排序和编码方式
  2. 请求过于频繁:实现请求限流机制,避免短时间内发送过多请求
  3. CSRF校验失败:确保请求头中包含正确的Referer信息
  4. WBI签名失败:定期更新img_key和sub_key,建议每24小时更新一次

测试报告生成

测试完成后,需要生成直观的测试报告,展示测试结果和关键指标。

def generate_report(test_results, output_file='api_test_report.md'):
    """生成测试报告"""
    with open(output_file, 'w', encoding='utf-8') as f:
        f.write('# B站API自动化测试报告\n\n')
        f.write(f'测试时间: {time.strftime("%Y-%m-%d %H:%M:%S")}\n\n')
        
        # 汇总统计
        total_cases = len(test_results)
        success_cases = sum(1 for r in test_results if r['success'])
        failure_cases = total_cases - success_cases
        
        f.write('## 测试汇总\n')
        f.write(f'| 总用例数 | 通过用例数 | 失败用例数 | 通过率 |\n')
        f.write(f'|----------|------------|------------|--------|\n')
        f.write(f'| {total_cases} | {success_cases} | {failure_cases} | {(success_cases/total_cases*100):.2f}% |\n\n')
        
        # 详细结果
        f.write('## 详细测试结果\n')
        for i, result in enumerate(test_results, 1):
            f.write(f'### 测试用例 {i}: {result["name"]}\n')
            f.write(f'- 状态: {"通过" if result["success"] else "失败"}\n')
            f.write(f'- API地址: {result["url"]}\n')
            f.write(f'- 请求方法: {result["method"]}\n')
            f.write(f'- 签名类型: {result["sign_type"]}\n')
            
            if not result["success"]:
                f.write(f'- 错误信息: {result["error"]}\n')
            
            f.write(f'- 响应时间: {result["response_time"]:.3f}s\n\n')
        
        # 性能指标
        if any('performance' in r for r in test_results):
            f.write('## 性能指标\n')
            for result in test_results:
                if 'performance' in result:
                    perf = result['performance']
                    f.write(f'### {result["name"]}\n')
                    f.write(f'- 平均响应时间: {perf["avg_time"]:.3f}s\n')
                    f.write(f'- P90响应时间: {perf["p90_time"]:.3f}s\n')
                    f.write(f'- 最大响应时间: {perf["max_time"]:.3f}s\n')
                    f.write(f'- 最小响应时间: {perf["min_time"]:.3f}s\n\n')

测试自动化与持续集成

为了实现测试的自动化和持续集成,我们可以使用GitHub Actions或其他CI/CD工具来定期运行测试用例,并生成测试报告。

GitHub Actions配置示例

name: API测试

on:
  schedule:
    - cron: '0 0 * * *'  # 每天运行一次
  push:
    branches: [ main ]
    paths:
      - 'docs/**'
      - '.github/workflows/api-test.yml'

jobs:
  test:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: '3.9'
    
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
    
    - name: Run API tests
      run: |
        python run_tests.py
    
    - name: Generate report
      run: |
        python generate_report.py
    
    - name: Upload report
      uses: actions/upload-artifact@v3
      with:
        name: api-test-report
        path: api_test_report.md

总结与展望

本文详细介绍了基于bilibili-API-collect项目的接口文档自动化测试方案,包括API签名机制解析、自动化测试框架设计、测试用例设计、错误处理和持续集成等方面。通过实施这套方案,开发者可以有效提高API测试效率,确保接口调用的稳定性和可靠性。

未来,我们可以从以下几个方面进一步完善测试方案:

  1. 增加接口覆盖率:不断完善测试用例,提高API接口的覆盖率
  2. 实时监控:建立API实时监控系统,及时发现接口异常
  3. 性能优化:基于测试结果,优化接口性能
  4. 自动化文档更新:结合测试结果,自动更新API文档

通过持续优化和完善测试方案,我们可以为B站API的使用者提供更加稳定、可靠的接口服务,促进相关应用生态的健康发展。

参考资料

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值