mcpField
Z
zero-script-qa

zero-script-qa

github.com/ww-w-ai测试与质量60648 次安装4 周前更新
代码仓库

关于 zero-script-qa

zero-script-qa 是一种通过结构化日志和实时监控开展 QA 的方法,面向开发与测试团队。它以人工体验测试结合 AI 日志分析,检测并记录问题,无需编写测试脚本。

主要功能

  1. 01结构化 JSON 日志规范
  2. 02跨服务 Request ID 追踪
  3. 03Docker 日志实时监控
  4. 04AI 分析错误与异常耗时
  5. 05自动整理 QA 问题

适用场景

  1. 01人工测试功能时实时发现错误
  2. 02按 Request ID 排查跨层请求
  3. 03监测慢响应与连续失败
  4. 04检查各环境的日志配置

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/ww-w-ai/bkit-claude-code --skill zero-script-qa

安装后在 Claude Code 中输入/zero-script-qa确认已加载。

详细介绍

零脚本 QA 专家知识

概述

零脚本 QA 是一种通过结构化日志和实时监控验证功能、无需编写测试脚本的方法。

Traditional: Write test code → Execute → Check results → Maintain
Zero Script: Build log infrastructure → Manual UX test → AI log analysis → Auto issue detection

核心原则

1. 记录所有内容
  • 所有 API 调用(包括 200 OK)
  • 所有错误
  • 所有重要业务事件
  • 通过 Request ID 跟踪整个流程
2. 结构化 JSON 日志
  • 可解析的 JSON 格式
  • 统一的字段(timestamp、level、request_id、message、data)
  • 为不同环境设置不同的日志级别
3. 实时监控
  • Docker 日志流
  • Claude Code 实时分析
  • 立即发现并记录问题

日志架构

JSON 日志格式标准
{
  "timestamp": "2026-01-08T10:30:00.000Z",
  "level": "INFO",
  "service": "api",
  "request_id": "req_abc123",
  "message": "API Request completed",
  "data": {
    "method": "POST",
    "path": "/api/users",
    "status": 200,
    "duration_ms": 45
  }
}
必需的日志字段
字段类型说明
timestampISO 8601发生时间
level字符串DEBUG、INFO、WARNING、ERROR
service字符串服务名称(api、web、worker 等)
request_id字符串请求跟踪 ID
message字符串日志消息
data对象附加数据(可选)
日志级别策略
环境最低级别用途
本地DEBUG开发和 QA
预发布DEBUGQA 和集成测试
生产INFO运维监控

Request ID 传播

概念
Client → API Gateway → Backend → Database
   ↓         ↓           ↓          ↓
req_abc   req_abc     req_abc    req_abc

Trackable with same Request ID across all layers
实现模式
1. 生成 Request ID(入口)
// middleware.ts
import { v4 as uuidv4 } from 'uuid';

export function generateRequestId(): string {
  return `req_${uuidv4().slice(0, 8)}`;
}

// Propagate via header
headers['X-Request-ID'] = requestId;
2. 提取并传播 Request ID
// API client
const requestId = headers['X-Request-ID'] || generateRequestId();

// Include in all logs
logger.info('Processing request', { request_id: requestId });

// Include in header when calling downstream services
await fetch(url, {
  headers: { 'X-Request-ID': requestId }
});

后端日志记录(FastAPI)

日志中间件
# middleware/logging.py
import logging
import time
import uuid
import json
from fastapi import Request

class JsonFormatter(logging.Formatter):
    def format(self, record):
        log_record = {
            "timestamp": self.formatTime(record),
            "level": record.levelname,
            "service": "api",
            "request_id": getattr(record, 'request_id', 'N/A'),
            "message": record.getMessage(),
        }
        if hasattr(record, 'data'):
            log_record["data"] = record.data
        return json.dumps(log_record)

class LoggingMiddleware:
    async def __call__(self, request: Request, call_next):
        request_id = request.headers.get('X-Request-ID', f'req_{uuid.uuid4().hex[:8]}')
        request.state.request_id = request_id

        start_time = time.time()

        # Request logging
        logger.info(
            f"Request started",
            extra={
                'request_id': request_id,
                'data': {
                    'method': request.method,
                    'path': request.url.path,
                    'query': str(request.query_params)
                }
            }
        )

        response = await call_next(request)

        duration = (time.time() - start_time) * 1000

        # Response logging (including 200 OK!)
        logger.info(
            f"Request completed",
            extra={
                'request_id': request_id,
                'data': {
                    'status': response.status_code,
                    'duration_ms': round(duration, 2)
                }
            }
        )

        response.headers['X-Request-ID'] = request_id
        return response
业务逻辑日志记录
# services/user_service.py
def create_user(data: dict, request_id: str):
    logger.info("Creating user", extra={
        'request_id': request_id,
        'data': {'email': data['email']}
    })

    # Business logic
    user = User(**data)
    db.add(user)
    db.commit()

    logger.info("User created", extra={
        'request_id': request_id,
        'data': {'user_id': user.id}
    })

    return user

前端日志记录(Next.js)

日志记录器模块
// lib/logger.ts
type LogLevel = 'DEBUG' | 'INFO' | 'WARNING' | 'ERROR';

interface LogData {
  request_id?: string;
  [key: string]: any;
}

const LOG_LEVELS: Record<LogLevel, number> = {
  DEBUG: 0,
  INFO: 1,
  WARNING: 2,
  ERROR: 3,
};

const MIN_LEVEL = process.env.NODE_ENV === 'production' ? 'INFO' : 'DEBUG';

function log(level: LogLevel, message: string, data?: LogData) {
  if (LOG_LEVELS[level] < LOG_LEVELS[MIN_LEVEL]) return;

  const logEntry = {
    timestamp: new Date().toISOString(),
    level,
    service: 'web',
    request_id: data?.request_id || 'N/A',
    message,
    data: data ? { ...data, request_id: undefined } : undefined,
  };

  console.log(JSON.stringify(logEntry));
}

export const logger = {
  debug: (msg: string, data?: LogData) => log('DEBUG', msg, data),
  info: (msg: string, data?: LogData) => log('INFO', msg, data),
  warning: (msg: string, data?: LogData) => log('WARNING', msg, data),
  error: (msg: string, data?: LogData) => log('ERROR', msg, data),
};
API 客户端集成
// lib/api-client.ts
import { logger } from './logger';
import { v4 as uuidv4 } from 'uuid';

export async function apiClient<T>(
  endpoint: string,
  options: RequestInit = {}
): Promise<T> {
  const requestId = `req_${uuidv4().slice(0, 8)}`;
  const startTime = Date.now();

  logger.info('API Request started', {
    request_id: requestId,
    method: options.method || 'GET',
    endpoint,
  });

  try {
    const response = await fetch(`/api${endpoint}`, {
      ...options,
      headers: {
        'Content-Type': 'application/json',
        'X-Request-ID': requestId,
        ...options.headers,
      },
    });

    const duration = Date.now() - startTime;
    const data = await response.json();

    // Log 200 OK too!
    logger.info('API Request completed', {
      request_id: requestId,
      status: response.status,
      duration_ms: duration,
    });

    if (!response.ok) {
      logger.error('API Request failed', {
        request_id: requestId,
        status: response.status,
        error: data.error,
      });
      throw new ApiError(data.error);
    }

    return data;
  } catch (error) {
    logger.error('API Request error', {
      request_id: requestId,
      error: error instanceof Error ? error.message : 'Unknown error',
    });
    throw error;
  }
}

Nginx JSON 日志

nginx.conf 配置
http {
    log_format json_combined escape=json '{'
        '"timestamp":"$time_iso8601",'
        '"level":"INFO",'
        '"service":"nginx",'
        '"request_id":"$http_x_request_id",'
        '"message":"HTTP Request",'
        '"data":{'
            '"remote_addr":"$remote_addr",'
            '"method":"$request_method",'
            '"uri":"$request_uri",'
            '"status":$status,'
            '"body_bytes_sent":$body_bytes_sent,'
            '"request_time":$request_time,'
            '"upstream_response_time":"$upstream_response_time",'
            '"http_referer":"$http_referer",'
            '"http_user_agent":"$http_user_agent"'
        '}'
    '}';

    access_log /var/log/nginx/access.log json_combined;
}

基于 Docker 的 QA 工作流

docker-compose.yml 配置
version: '3.8'
services:
  api:
    build: ./backend
    environment:
      - LOG_LEVEL=DEBUG
      - LOG_FORMAT=json
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

  web:
    build: ./frontend
    environment:
      - NODE_ENV=development
    depends_on:
      - api

  nginx:
    image: nginx:alpine
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
    ports:
      - "80:80"
    depends_on:
      - api
      - web
实时日志监控
# Stream all service logs
docker compose logs -f

# Specific service only
docker compose logs -f api

# Filter errors only
docker compose logs -f | grep '"level":"ERROR"'

# Track specific Request ID
docker compose logs -f | grep 'req_abc123'

QA 自动化工作流

1. 启动环境
# Start development environment
docker compose up -d

# Start log monitoring (Claude Code monitors)
docker compose logs -f
2. 手动 UX 测试
User tests actual features in browser:
1. Sign up attempt
2. Login attempt
3. Use core features
4. Test edge cases
3. Claude Code 日志分析
Claude Code in real-time:
1. Monitor log stream
2. Detect error patterns
3. Detect abnormal response times
4. Track entire flow via Request ID
5. Auto-document issues
4. 问题记录
# QA Issue Report

## Issues Found

### ISSUE-001: Insufficient error handling on login failure
- **Request ID**: req_abc123
- **Severity**: Medium
- **Reproduction path**: Login → Wrong password
- **Log**:
  ```json
  {"level":"ERROR","message":"Login failed","data":{"error":"Invalid credentials"}}
  • 问题:错误消息对用户不够友好
  • 建议修复:添加错误代码与消息的映射

---

## Issue Detection Patterns

### 1. Error Detection
```json
{"level":"ERROR","message":"..."}

→ 立即报告

2. 检测响应缓慢
{"data":{"duration_ms":3000}}

→ 超过 1000ms 时发出警告

3. 检测连续失败
3+ consecutive failures on same endpoint

→ 报告潜在的系统问题

4. 异常状态代码
{"data":{"status":500}}

→ 立即报告 5xx 错误


阶段集成

阶段零脚本 QA 集成
阶段 4(API)验证 API 响应日志
阶段 6(UI)验证前端日志
阶段 7(安全)验证安全事件日志
阶段 8(审查)审查日志质量
阶段 9(部署)配置生产日志级别

迭代测试周期模式

基于 bkamp.ai 通知功能开发:

示例:8 轮测试流程
轮次通过率发现的 Bug已应用的修复
第 1 轮30%DB 架构不匹配架构迁移
第 2 轮45%缺少 NULL 处理添加空值检查
第 3 轮55%路由错误修复 deeplinks
第 4 轮65%类型不匹配修复枚举类型
第 5 轮70%计算错误修复计数逻辑
第 6 轮75%缺少事件添加事件触发器
第 7 轮82%缓存同步问题修复缓存失效
第 8 轮89%稳定最终完善
周期工作流
┌─────────────────────────────────────────────────────────────┐
│                   Iterative Test Cycle                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Cycle N:                                                   │
│  1. Run test script (E2E or manual)                         │
│  2. Claude monitors logs in real-time                       │
│  3. Record pass/fail results                                │
│  4. Claude identifies root cause of failures                │
│  5. Fix code immediately (hot reload)                       │
│  6. Document: Cycle N → Bug → Fix                           │
│                                                             │
│  Repeat until acceptable pass rate (>85%)                   │
│                                                             │
└─────────────────────────────────────────────────────────────┘
E2E 测试脚本模板
#!/bin/bash
# E2E Test Script Template

API_URL="http://localhost:8000"
TOKEN="your-test-token"

PASS_COUNT=0
FAIL_COUNT=0
SKIP_COUNT=0

GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[0;33m'
NC='\033[0m'

test_feature_action() {
    echo -n "Testing: Feature action... "

    response=$(curl -s -X POST "$API_URL/api/v1/feature/action" \
        -H "Authorization: Bearer $TOKEN" \
        -H "Content-Type: application/json" \
        -d '{"param": "value"}')

    if [[ "$response" == *"expected_result"* ]]; then
        echo -e "${GREEN}✅ PASS${NC}"
        ((PASS_COUNT++))
    else
        echo -e "${RED}❌ FAIL${NC}"
        echo "Response: $response"
        ((FAIL_COUNT++))
    fi
}

# Run all tests
test_feature_action
# ... more tests

# Summary
echo ""
echo "═══════════════════════════════════════"
echo "Test Results:"
echo -e "  ${GREEN}✅ PASS: $PASS_COUNT${NC}"
echo -e "  ${RED}❌ FAIL: $FAIL_COUNT${NC}"
echo -e "  ${YELLOW}⏭️  SKIP: $SKIP_COUNT${NC}"
echo "═══════════════════════════════════════"
测试周期记录模板
# Feature Test Results - Cycle N

## Summary
- **Date**: YYYY-MM-DD
- **Feature**: {feature name}
- **Pass Rate**: N%
- **Tests**: X passed / Y total

## Results

| Test Case | Status | Notes |
|-----------|--------|-------|
| Test 1 | ✅ | |
| Test 2 | ❌ | {error description} |
| Test 3 | ⏭️ | {skip reason} |

## Bugs Found

### BUG-001: {Title}
- **Root Cause**: {description}
- **Fix**: {what was changed}
- **Files**: `path/to/file.py:123`

## Next Cycle Plan
- {what to test next}

检查清单

日志基础设施
  • 已应用 JSON 日志格式
  • Request ID 生成与传播
  • 为各环境设置日志级别
  • Docker 日志配置
后端日志记录
  • 已实现日志中间件
  • 记录所有 API 调用(包括 200 OK)
  • 业务逻辑日志记录
  • 详细记录错误
前端日志记录
  • 已实现 Logger 模块
  • 已集成 API 客户端
  • 已实现错误边界日志记录
QA 工作流
  • 已配置 Docker Compose
  • 已准备好实时监控
  • 已准备好问题文档模板

自动应用规则

构建日志基础设施时

实现 API/后端时:

  1. 建议创建日志中间件
  2. 建议设置 JSON 格式的日志记录器
  3. 添加 Request ID 生成/传递逻辑

实现前端时:

  1. 建议创建 Logger 模块
  2. 建议将日志记录集成到 API 客户端
  3. 建议包含 Request ID 请求头
执行 QA 时

收到测试请求时:

  1. 指导运行 docker compose logs -f
  2. 请求用户手动测试 UX
  3. 实时监控日志
  4. 发现问题后立即记录
  5. 提供修复建议
问题检测阈值
严重级别条件操作
严重level: ERROR 或 status: 5xx立即报告
严重duration_ms > 3000立即报告
严重连续失败 3 次或以上立即报告
警告status: 401, 403发出警告报告
警告duration_ms > 1000发出警告报告
信息缺少日志字段记录为待改进项
信息未传递 Request ID记录为待改进项
必需的日志位置
后端(FastAPI/Express)
✅ Request start (method, path, params)
✅ Request complete (status, duration_ms)
✅ Major business logic steps
✅ Detailed info on errors
✅ Before/after external API calls
✅ DB queries (in development)
前端(Next.js/React)
✅ API call start
✅ API response received (status, duration)
✅ Detailed info on errors
✅ Important user actions

评论

支持 Markdown