⚠️ Alpha内测版本警告:此为早期内部构建版本,尚不完整且可能存在错误,欢迎大家提Issue反馈问题或建议
Skip to content

9.2.2 测试专用的配置——环境变量:测试专用配置管理

环境变量是连接代码与环境的桥梁,管理好它们是测试成功的基础。

环境变量文件层级

project/
├── .env                  # 默认配置(被其他覆盖)
├── .env.local            # 本地开发配置(不提交 git)
├── .env.development      # 开发环境配置
├── .env.test             # 测试环境配置
├── .env.production       # 生产环境配置
└── .env.example          # 配置模板(提交 git)

加载优先级

.env.test 标准配置

bash
# .env.test

# 环境标识
NODE_ENV=test

# 数据库(必须使用测试数据库)
DATABASE_URL="postgresql://test:test@localhost:5432/myapp_test"

# 认证(使用固定的测试密钥)
JWT_SECRET="test-jwt-secret-do-not-use-in-production"
NEXTAUTH_SECRET="test-nextauth-secret"
NEXTAUTH_URL="http://localhost:3000"

# 外部服务(使用测试模式或 Mock)
STRIPE_SECRET_KEY="sk_test_..."
STRIPE_WEBHOOK_SECRET="whsec_test_..."

# 邮件服务(禁用或使用测试服务)
SMTP_HOST=""
SMTP_PORT=""

# 日志级别(测试时可以调高)
LOG_LEVEL="error"

# 测试专用配置
TEST_USER_EMAIL="test@example.com"
TEST_USER_PASSWORD="TestPassword123!"

使用 dotenv-cli 加载测试配置

bash
# 安装 dotenv-cli
npm install -D dotenv-cli
json
// package.json
{
  "scripts": {
    "test": "dotenv -e .env.test -- jest",
    "test:watch": "dotenv -e .env.test -- jest --watch",
    "test:coverage": "dotenv -e .env.test -- jest --coverage",
    "test:ci": "dotenv -e .env.test -- jest --ci --runInBand"
  }
}

在测试中访问环境变量

typescript
// lib/env.ts
import { z } from 'zod';

const envSchema = z.object({
  NODE_ENV: z.enum(['development', 'test', 'production']),
  DATABASE_URL: z.string().url(),
  JWT_SECRET: z.string().min(32),
  // 测试环境可选的配置
  STRIPE_SECRET_KEY: z.string().optional(),
});

export const env = envSchema.parse(process.env);

// 便捷判断
export const isTest = env.NODE_ENV === 'test';
export const isProd = env.NODE_ENV === 'production';
typescript
// __tests__/example.test.ts
import { env, isTest } from '@/lib/env';

describe('环境配置', () => {
  it('应处于测试环境', () => {
    expect(isTest).toBe(true);
    expect(env.NODE_ENV).toBe('test');
  });

  it('应使用测试数据库', () => {
    expect(env.DATABASE_URL).toContain('_test');
  });
});

敏感配置的处理

不应该在 .env.test 中出现的内容

bash
# .env.test

# ❌ 错误:不要使用真实的生产密钥
STRIPE_SECRET_KEY="sk_live_xxx"

# ✅ 正确:使用测试模式密钥
STRIPE_SECRET_KEY="sk_test_xxx"

# ❌ 错误:不要使用真实的生产数据库
DATABASE_URL="postgresql://user:pass@prod-server/myapp"

# ✅ 正确:使用本地测试数据库
DATABASE_URL="postgresql://test:test@localhost/myapp_test"

.gitignore 配置

bash
# .gitignore

# 所有本地环境文件
.env.local
.env.*.local

# 测试环境文件(如果包含敏感信息)
# .env.test

# 但要保留示例文件
!.env.example

环境变量验证

typescript
// test/setup.ts
import { z } from 'zod';

const testEnvSchema = z.object({
  NODE_ENV: z.literal('test'),
  DATABASE_URL: z.string().refine(
    (url) => url.includes('_test') || url.includes('localhost'),
    { message: '测试必须使用测试数据库' }
  ),
});

beforeAll(() => {
  const result = testEnvSchema.safeParse(process.env);
  
  if (!result.success) {
    console.error('环境变量验证失败:', result.error.format());
    throw new Error('测试环境配置错误');
  }
});

动态配置切换

typescript
// lib/config.ts
type Environment = 'development' | 'test' | 'production';

interface Config {
  apiBaseUrl: string;
  enableLogging: boolean;
  mockExternalServices: boolean;
}

const configs: Record<Environment, Config> = {
  development: {
    apiBaseUrl: 'http://localhost:3000',
    enableLogging: true,
    mockExternalServices: false,
  },
  test: {
    apiBaseUrl: 'http://localhost:3000',
    enableLogging: false,
    mockExternalServices: true, // 测试时 Mock 外部服务
  },
  production: {
    apiBaseUrl: 'https://api.example.com',
    enableLogging: true,
    mockExternalServices: false,
  },
};

export const config = configs[process.env.NODE_ENV as Environment] || configs.development;

CI/CD 中的环境变量

yaml
# .github/workflows/test.yml
name: Test
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    
    env:
      NODE_ENV: test
      DATABASE_URL: postgresql://test:test@localhost:5432/myapp_test
      JWT_SECRET: ${{ secrets.TEST_JWT_SECRET }}
    
    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_USER: test
          POSTGRES_PASSWORD: test
          POSTGRES_DB: myapp_test
        ports:
          - 5432:5432
    
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
      - run: npm ci
      - run: npm run test:ci

常见问题解决

问题原因解决方案
环境变量未加载dotenv-cli 未安装npm i -D dotenv-cli
使用了生产配置文件优先级问题检查 .env.local
CI 中变量为空secrets 未配置在 GitHub 设置中添加
类型错误环境变量都是字符串使用 zod 转换

本节小结

测试环境变量管理的核心原则是:隔离、验证、安全。使用 .env.test 隔离测试配置,使用 zod 验证环境变量正确性,避免在测试配置中暴露敏感信息。配合 dotenv-cli,可以轻松在不同环境间切换。