Meixiong Niannian画图引擎软件测试指南:自动化测试实战

📅 发布时间:2026/7/12 13:24:09 👁️ 浏览次数:
Meixiong Niannian画图引擎软件测试指南:自动化测试实战
Meixiong Niannian画图引擎软件测试指南自动化测试实战你是不是也遇到过这种情况辛辛苦苦开发了一个画图引擎的新功能结果一上线用户反馈说生成的图片颜色不对或者干脆就报错崩溃了。更头疼的是这种问题往往不是每次都能复现有时候跑得好好的有时候就突然出问题。我之前就吃过这样的亏。那时候我们团队给Meixiong Niannian画图引擎加了一个新的风格化滤镜本地测试一切正常结果部署到线上后有用户反馈说在处理某些特定尺寸的图片时会卡死。排查了半天才发现是内存管理的一个边界条件没处理好。从那以后我就明白了对于AI画图引擎这种复杂的系统光靠手动测试是远远不够的。你需要一套可靠的自动化测试体系确保每次更新都不会破坏原有的功能。今天我就来分享一下我是如何为Meixiong Niannian画图引擎搭建自动化测试框架的。1. 为什么画图引擎需要自动化测试你可能觉得画图引擎不就是输入文字出图片吗有什么好测试的但实际上这里面的水可深了。首先画图引擎的输出是图片而图片的质量很难用简单的对错来判断。一张图有没有按照提示词的要求生成颜色搭配是否合理细节是否到位这些都需要验证。其次画图引擎通常运行在GPU上涉及到显存管理、模型加载、推理优化等一系列复杂操作。任何一个环节出问题都可能导致整个系统崩溃。最后用户的使用场景千变万化。有人用简单的提示词有人用复杂的组合指令有人生成小图有人要4K高清有人用默认参数有人自定义各种设置。这些都需要测试覆盖。手动测试这些场景几乎是不可能的任务。你不可能每次更新都把所有可能的组合都试一遍。这就是为什么我们需要自动化测试——让机器帮我们做这些重复性的验证工作。2. 测试环境搭建与基础配置在开始写测试用例之前我们需要先把测试环境搭起来。这里我假设你已经有了一个可以运行的Meixiong Niannian画图引擎实例。2.1 环境准备我推荐使用Python作为测试语言因为它有丰富的测试框架和图像处理库。首先安装必要的依赖pip install pytest pytest-asyncio pillow opencv-python numpy requestspytest我们的主力测试框架pytest-asyncio用于异步测试画图引擎的API通常是异步的pillow和opencv-python用于图像处理和验证numpy数值计算requests调用HTTP API2.2 测试配置文件创建一个config.py文件来管理测试配置import os from dataclasses import dataclass dataclass class TestConfig: 测试配置 # 画图引擎的API地址 api_base_url: str os.getenv(MEIXIONG_API_URL, http://localhost:7860) # 测试用的API密钥如果有的话 api_key: str os.getenv(MEIXIONG_API_KEY, ) # 测试输出目录 output_dir: str os.getenv(TEST_OUTPUT_DIR, ./test_outputs) # 测试图片保存设置 save_test_images: bool bool(os.getenv(SAVE_TEST_IMAGES, True)) # 超时设置秒 request_timeout: int 60 generation_timeout: int 300 # 测试图片尺寸 test_width: int 512 test_height: int 512 # 允许的生成时间偏差秒 generation_time_tolerance: float 5.0 # 全局配置实例 config TestConfig() # 创建输出目录 os.makedirs(config.output_dir, exist_okTrue)这样配置的好处是灵活。你可以在环境变量中覆盖这些配置方便在不同的环境开发、测试、生产中运行测试。3. 核心功能测试用例设计现在我们来设计具体的测试用例。我会按照功能模块来组织测试确保每个核心功能都有对应的验证。3.1 基础文本生成图片测试这是最核心的功能测试。我们需要验证画图引擎能正确理解提示词并生成对应的图片。import pytest import asyncio import aiohttp from PIL import Image import numpy as np from config import config class TestTextToImage: 文本生成图片测试 pytest.mark.asyncio async def test_basic_text_to_image(self): 测试基础文本生成图片功能 async with aiohttp.ClientSession() as session: # 准备请求数据 payload { prompt: a cute cat sitting on a sofa, cartoon style, negative_prompt: blurry, low quality, distorted, width: config.test_width, height: config.test_height, num_inference_steps: 20, guidance_scale: 7.5, seed: 42 # 固定种子确保可重复性 } # 添加API密钥如果需要 if config.api_key: payload[api_key] config.api_key # 发送生成请求 async with session.post( f{config.api_base_url}/api/generate, jsonpayload, timeoutconfig.request_timeout ) as response: assert response.status 200, fAPI返回状态码错误: {response.status} result await response.json() assert image in result, 响应中缺少image字段 assert generation_time in result, 响应中缺少generation_time字段 # 验证生成时间在合理范围内 gen_time result[generation_time] assert gen_time config.generation_timeout, f生成时间过长: {gen_time}秒 # 如果有base64编码的图片可以解码验证 if image_base64 in result: import base64 from io import BytesIO # 解码图片 image_data base64.b64decode(result[image_base64]) image Image.open(BytesIO(image_data)) # 验证图片尺寸 assert image.size (config.test_width, config.test_height), \ f图片尺寸不正确: {image.size} # 验证图片不是全黑或全白简单的有效性检查 img_array np.array(image) mean_value img_array.mean() assert 10 mean_value 245, f图片可能无效平均像素值: {mean_value} # 保存测试图片可选 if config.save_test_images: image.save(f{config.output_dir}/test_basic_cat.png) pytest.mark.asyncio async def test_chinese_prompt(self): 测试中文提示词 async with aiohttp.ClientSession() as session: payload { prompt: 一只可爱的熊猫在竹林里吃竹子水墨画风格, width: config.test_width, height: config.test_height, num_inference_steps: 25 } async with session.post( f{config.api_base_url}/api/generate, jsonpayload, timeoutconfig.request_timeout ) as response: assert response.status 200 result await response.json() assert image in result pytest.mark.asyncio async def test_empty_prompt(self): 测试空提示词应该返回错误 async with aiohttp.ClientSession() as session: payload { prompt: , width: config.test_width, height: config.test_height } async with session.post( f{config.api_base_url}/api/generate, jsonpayload, timeoutconfig.request_timeout ) as response: # 空提示词应该返回错误 assert response.status 400, 空提示词应该返回400错误3.2 图片编辑功能测试除了文本生成画图引擎通常还有图片编辑功能比如图生图、局部重绘等。class TestImageEditing: 图片编辑功能测试 pytest.mark.asyncio async def test_img2img(self): 测试图生图功能 # 首先需要一张基础图片 base_image self._create_test_image() async with aiohttp.ClientSession() as session: # 将图片转换为base64 import base64 from io import BytesIO buffered BytesIO() base_image.save(buffered, formatPNG) img_str base64.b64encode(buffered.getvalue()).decode() payload { prompt: make it sunset style with orange sky, init_image: img_str, strength: 0.7, # 重绘强度 width: config.test_width, height: config.test_height } async with session.post( f{config.api_base_url}/api/img2img, jsonpayload, timeoutconfig.request_timeout ) as response: assert response.status 200 result await response.json() assert image in result # 验证编辑后的图片与原始图片不同 if image_base64 in result: edited_data base64.b64decode(result[image_base64]) edited_image Image.open(BytesIO(edited_data)) # 计算图片差异 diff np.array(edited_image).astype(float) - np.array(base_image).astype(float) diff_norm np.linalg.norm(diff) # 编辑后的图片应该与原始图片有显著差异 assert diff_norm 1000, 图生图编辑效果不明显 def _create_test_image(self): 创建测试用的基础图片 from PIL import Image, ImageDraw # 创建一个简单的测试图片 image Image.new(RGB, (config.test_width, config.test_height), colorwhite) draw ImageDraw.Draw(image) # 画一个简单的蓝色矩形 draw.rectangle([50, 50, 200, 200], fillblue) return image3.3 批量生成测试在实际使用中用户经常需要批量生成图片。我们需要测试这个功能的稳定性和性能。class TestBatchGeneration: 批量生成测试 pytest.mark.asyncio async def test_batch_generation(self): 测试批量生成多张图片 async with aiohttp.ClientSession() as session: payload { prompt: a beautiful landscape with mountains and lake, batch_size: 4, # 一次生成4张 width: 256, # 用小尺寸加快测试速度 height: 256, num_inference_steps: 15 } async with session.post( f{config.api_base_url}/api/generate_batch, jsonpayload, timeoutconfig.request_timeout * 2 # 批量生成需要更多时间 ) as response: assert response.status 200 result await response.json() # 验证返回了正确数量的图片 assert images in result images result[images] assert len(images) payload[batch_size], \ f返回的图片数量不正确: {len(images)} # 验证每张图片都是有效的 for i, img_data in enumerate(images): assert image in img_data # 如果有base64数据可以进一步验证 if image_base64 in img_data: import base64 from io import BytesIO image Image.open(BytesIO(base64.b64decode(img_data[image_base64]))) assert image.size (256, 256) if config.save_test_images: image.save(f{config.output_dir}/batch_{i}.png) pytest.mark.asyncio async def test_batch_with_different_prompts(self): 测试用不同的提示词批量生成 prompts [ a red apple on a wooden table, a blue car on a rainy street, a green forest with sunlight, a yellow sunflower field ] async with aiohttp.ClientSession() as session: payload { prompts: prompts, # 多个不同的提示词 width: 256, height: 256, num_inference_steps: 15 } async with session.post( f{config.api_base_url}/api/generate_batch_multi, jsonpayload, timeoutconfig.request_timeout * 3 ) as response: assert response.status 200 result await response.json() # 应该为每个提示词生成一张图片 assert len(result[images]) len(prompts)4. 性能与稳定性测试功能正确性只是基础我们还需要确保画图引擎的性能和稳定性。4.1 并发压力测试模拟多个用户同时使用的情况测试系统的并发处理能力。import asyncio from datetime import datetime class TestPerformance: 性能测试 pytest.mark.asyncio async def test_concurrent_requests(self): 测试并发请求 num_requests 10 # 并发请求数量 prompt a simple test image, minimal style async def single_request(session, request_id): 单个请求任务 start_time datetime.now() payload { prompt: f{prompt} - request {request_id}, width: 128, # 用小尺寸减少负载 height: 128, num_inference_steps: 10 # 减少步数加快速度 } try: async with session.post( f{config.api_base_url}/api/generate, jsonpayload, timeout30 ) as response: end_time datetime.now() duration (end_time - start_time).total_seconds() if response.status 200: return {success: True, duration: duration, request_id: request_id} else: return {success: False, duration: duration, request_id: request_id} except Exception as e: end_time datetime.now() duration (end_time - start_time).total_seconds() return {success: False, error: str(e), duration: duration, request_id: request_id} # 创建并发任务 async with aiohttp.ClientSession() as session: tasks [single_request(session, i) for i in range(num_requests)] results await asyncio.gather(*tasks) # 统计结果 successful sum(1 for r in results if r[success]) durations [r[duration] for r in results if r[success]] print(f\n并发测试结果:) print(f总请求数: {num_requests}) print(f成功数: {successful}) print(f成功率: {successful/num_requests*100:.1f}%) if durations: print(f平均响应时间: {sum(durations)/len(durations):.2f}秒) print(f最快响应: {min(durations):.2f}秒) print(f最慢响应: {max(durations):.2f}秒) # 断言成功率应该高于90% assert successful / num_requests 0.9, f并发测试成功率过低: {successful/num_requests*100:.1f}% pytest.mark.asyncio async def test_memory_usage(self): 测试内存使用情况长时间运行 # 连续生成多张图片监控内存使用 import psutil import os process psutil.Process(os.getpid()) memory_before process.memory_info().rss / 1024 / 1024 # MB async with aiohttp.ClientSession() as session: for i in range(5): # 连续生成5张图片 payload { prompt: ftest image for memory usage check {i}, width: 512, height: 512, num_inference_steps: 20 } async with session.post( f{config.api_base_url}/api/generate, jsonpayload, timeoutconfig.request_timeout ) as response: assert response.status 200 memory_after process.memory_info().rss / 1024 / 1024 memory_increase memory_after - memory_before print(f\n内存使用测试:) print(f初始内存: {memory_before:.1f} MB) print(f结束内存: {memory_after:.1f} MB) print(f内存增加: {memory_increase:.1f} MB) # 内存增加应该在合理范围内 # 注意这个阈值需要根据实际情况调整 assert memory_increase 500, f内存泄漏可能: 增加了 {memory_increase:.1f} MB4.2 错误处理测试测试系统在异常情况下的表现确保不会崩溃。class TestErrorHandling: 错误处理测试 pytest.mark.asyncio async def test_invalid_image_size(self): 测试无效的图片尺寸 invalid_sizes [ (0, 512), # 宽度为0 (512, 0), # 高度为0 (10000, 512), # 宽度过大 (512, 10000), # 高度过大 (-100, 512), # 负宽度 (512, -100) # 负高度 ] async with aiohttp.ClientSession() as session: for width, height in invalid_sizes: payload { prompt: test, width: width, height: height } async with session.post( f{config.api_base_url}/api/generate, jsonpayload, timeoutconfig.request_timeout ) as response: # 无效尺寸应该返回错误 assert response.status in [400, 422], \ f无效尺寸({width}x{height})应该返回错误但得到了{response.status} pytest.mark.asyncio async def test_malformed_json(self): 测试格式错误的JSON请求 async with aiohttp.ClientSession() as session: # 发送无效的JSON数据 invalid_json {this is not valid json} async with session.post( f{config.api_base_url}/api/generate, datainvalid_json, headers{Content-Type: application/json}, timeoutconfig.request_timeout ) as response: # 应该返回400错误 assert response.status 400, 无效JSON应该返回400错误 pytest.mark.asyncio async def test_missing_required_fields(self): 测试缺少必填字段 test_cases [ {}, # 完全空 {width: 512, height: 512}, # 缺少prompt {prompt: test}, # 缺少尺寸 ] async with aiohttp.ClientSession() as session: for payload in test_cases: async with session.post( f{config.api_base_url}/api/generate, jsonpayload, timeoutconfig.request_timeout ) as response: assert response.status in [400, 422], \ f缺少必填字段应该返回错误: {payload}5. 测试执行与持续集成有了测试用例我们还需要一个方便的方式来执行它们并集成到开发流程中。5.1 测试运行脚本创建一个run_tests.py脚本#!/usr/bin/env python3 Meixiong Niannian画图引擎自动化测试运行脚本 import sys import os import argparse import subprocess from datetime import datetime def run_tests(test_typeall, output_dir./test_reports): 运行测试 # 创建输出目录 os.makedirs(output_dir, exist_okTrue) # 生成时间戳 timestamp datetime.now().strftime(%Y%m%d_%H%M%S) # 根据测试类型选择不同的pytest参数 if test_type all: test_path tests/ report_file f{output_dir}/test_report_{timestamp}.html junit_file f{output_dir}/junit_{timestamp}.xml elif test_type functional: test_path tests/test_functional.py report_file f{output_dir}/functional_report_{timestamp}.html junit_file f{output_dir}/junit_functional_{timestamp}.xml elif test_type performance: test_path tests/test_performance.py report_file f{output_dir}/performance_report_{timestamp}.html junit_file f{output_dir}/junit_performance_{timestamp}.xml else: print(f未知的测试类型: {test_type}) return False print(f开始运行{test_type}测试...) print(f测试报告将保存到: {report_file}) # 构建pytest命令 cmd [ pytest, test_path, -v, # 详细输出 f--html{report_file}, # HTML报告 f--junitxml{junit_file}, # JUnit格式报告用于CI --tbshort, # 简化的错误回溯 ] # 如果是性能测试添加标记 if test_type performance: cmd.append(-m) cmd.append(performance) # 执行测试 try: result subprocess.run(cmd, checkTrue) print(f\n测试完成报告已生成: {report_file}) return True except subprocess.CalledProcessError as e: print(f\n测试失败退出码: {e.returncode}) return False def main(): 主函数 parser argparse.ArgumentParser(description运行Meixiong Niannian画图引擎自动化测试) parser.add_argument( --type, choices[all, functional, performance], defaultall, help测试类型默认: all ) parser.add_argument( --output, default./test_reports, help测试报告输出目录默认: ./test_reports ) args parser.parse_args() # 设置环境变量如果需要 os.environ[MEIXIONG_API_URL] os.getenv(MEIXIONG_API_URL, http://localhost:7860) os.environ[SAVE_TEST_IMAGES] False # 在CI中通常不保存图片 success run_tests(args.type, args.output) if not success: sys.exit(1) if __name__ __main__: main()5.2 GitHub Actions集成示例如果你使用GitHub可以创建一个.github/workflows/test.yml文件name: Meixiong Niannian Tests on: push: branches: [ main, develop ] pull_request: branches: [ main ] jobs: test: runs-on: ubuntu-latest services: meixiong: image: meixiong/niannian:latest ports: - 7860:7860 options: - --gpus all --shm-size8g steps: - uses: actions/checkoutv3 - name: Set up Python uses: actions/setup-pythonv4 with: python-version: 3.9 - name: Install dependencies run: | python -m pip install --upgrade pip pip install pytest pytest-asyncio pytest-html pillow opencv-python numpy requests aiohttp - name: Wait for Meixiong to be ready run: | timeout 300 bash -c until curl -s http://localhost:7860/health /dev/null; do echo Waiting for Meixiong Niannian to start... sleep 5 done - name: Run functional tests run: | python run_tests.py --type functional --output ./test-reports env: MEIXIONG_API_URL: http://localhost:7860 - name: Upload test reports if: always() uses: actions/upload-artifactv3 with: name: test-reports path: test-reports/ - name: Run performance tests (on schedule only) if: github.event_name schedule run: | python run_tests.py --type performance --output ./performance-reports env: MEIXIONG_API_URL: http://localhost:78606. 测试报告与监控测试不仅要运行还要有好的报告和监控。6.1 自定义测试报告我们可以扩展pytest来生成更详细的测试报告# conftest.py import pytest from datetime import datetime import json import os def pytest_configure(config): pytest配置钩子 # 创建测试结果目录 if not hasattr(config, workerinput): # 避免在xdist worker中重复创建 os.makedirs(./test_results, exist_okTrue) def pytest_sessionfinish(session, exitstatus): 测试会话结束时的钩子 # 收集测试结果统计 passed len(session.items) - session.testsfailed - session.testscollected failed session.testsfailed # 生成自定义报告 report_data { timestamp: datetime.now().isoformat(), total_tests: len(session.items), passed: passed, failed: failed, success_rate: passed / len(session.items) * 100 if len(session.items) 0 else 0, duration: session.duration } # 保存报告 with open(./test_results/summary.json, w) as f: json.dump(report_data, f, indent2) print(f\n{*50}) print(f测试完成!) print(f总计: {len(session.items)} 个测试) print(f通过: {passed}) print(f失败: {failed}) print(f成功率: {report_data[success_rate]:.1f}%) print(f耗时: {session.duration:.2f} 秒) print(f{*50})6.2 测试结果可视化创建一个简单的HTML报告生成器# generate_report.py import json from datetime import datetime import plotly.graph_objects as go from plotly.subplots import make_subplots def generate_test_report(): 生成测试报告 # 读取测试结果 with open(./test_results/summary.json, r) as f: data json.load(f) # 创建图表 fig make_subplots( rows2, cols2, subplot_titles(测试结果分布, 成功率趋势, 测试耗时, 详细统计), specs[[{type: pie}, {type: scatter}], [{type: bar}, {type: table}]] ) # 饼图测试结果分布 fig.add_trace( go.Pie( labels[通过, 失败], values[data[passed], data[failed]], hole0.3, marker_colors[#00CC96, #EF553B] ), row1, col1 ) # 表格详细统计 fig.add_trace( go.Table( headerdict( values[指标, 数值], fill_colorlightgrey, alignleft ), cellsdict( values[ [总计测试, 通过数, 失败数, 成功率, 耗时], [ data[total_tests], data[passed], data[failed], f{data[success_rate]:.1f}%, f{data[duration]:.2f}秒 ] ], alignleft ) ), row2, col2 ) # 更新布局 fig.update_layout( title_textfMeixiong Niannian测试报告 - {data[timestamp]}, height800, showlegendTrue ) # 保存报告 fig.write_html(./test_results/test_report.html) print(测试报告已生成: ./test_results/test_report.html) if __name__ __main__: generate_test_report()7. 总结与建议为Meixiong Niannian画图引擎搭建自动化测试体系看起来工作量不小但实际带来的价值是巨大的。从我自己的经验来看有了这套测试体系后发布信心大大增强每次发布新版本前跑一遍测试基本就能确定核心功能是否正常。问题发现更早很多潜在问题在开发阶段就被测试发现了不用等到用户反馈。回归测试省时省力修复一个bug后跑一下相关测试确保没有引入新的问题。性能监控自动化定期运行性能测试及时发现性能退化。我建议你可以从基础的功能测试开始先确保核心的文本生成图片功能稳定。然后逐步添加更多的测试用例覆盖图片编辑、批量生成等高级功能。最后再考虑性能测试和压力测试。测试不是一次性的工作而是一个持续的过程。随着画图引擎功能的增加测试用例也需要不断更新和维护。但相信我这个投入是值得的。它不仅能提高软件质量还能让你在晚上睡得更安稳——不用担心半夜被用户的报错电话吵醒。获取更多AI镜像想探索更多AI镜像和应用场景访问 CSDN星图镜像广场提供丰富的预置镜像覆盖大模型推理、图像生成、视频生成、模型微调等多个领域支持一键部署。