Logon8n中文教程

调试与测试

掌握N8N工作流的调试技巧和测试方法,确保自动化系统稳定运行

调试与测试

调试和测试是确保工作流稳定运行的关键技能。本章将教你如何有效调试 N8N 工作流,以及如何建立完善的测试流程。

🔍 调试基础

N8N 调试工具概览

工具用途位置适用场景
执行历史查看历史执行记录右侧面板排查历史问题
节点输出查看节点数据节点下方数据流追踪
错误信息查看具体错误节点红色标记定位错误原因
Console日志自定义调试信息浏览器控制台深度调试

执行模式

// 测试执行(Test)
// - 只执行一次
// - 显示详细数据
// - 不保存到执行历史

// 正常执行(Execute)  
// - 完整执行流程
// - 保存执行历史
// - 触发所有节点

// 手动执行(Manual)
// - 跳过触发器
// - 从指定节点开始
// - 用于部分测试

🐛 常见调试场景

1. 数据流问题调试

问题:数据在节点间传递异常

调试步骤

// 1. 在问题节点前添加 Set 节点检查数据
{
  "debug_node_name": "before_problem_node",
  "debug_data_type": "{{ typeof $json }}",
  "debug_data_keys": "{{ Object.keys($json) }}",
  "debug_item_count": "{{ $input.all().length }}",
  "debug_sample_data": "{{ JSON.stringify($json, null, 2) }}",
  "original_data": "{{ $json }}"
}

// 2. 使用 Function 节点详细分析
const items = $input.all();
console.log('Total items:', items.length);

items.forEach((item, index) => {
  console.log(`Item ${index}:`, {
    type: typeof item.json,
    keys: Object.keys(item.json),
    values: item.json
  });
});

// 检查数据完整性
const hasRequiredFields = items.every(item => 
  item.json.id && item.json.email
);
console.log('All items have required fields:', hasRequiredFields);

return items;

2. API 调用问题调试

问题:HTTP Request 节点调用失败

调试方法

// 1. 在 HTTP Request 节点中启用详细日志
// Settings → 
Continue On Fail: true  // 继续执行不中断
Response Format: "Auto-detect"

// 2. 添加错误处理 Function 节点
const response = $input.first().json;

if (response.error) {
  console.error('API Error:', {
    status: response.error.httpCode,
    message: response.error.message,
    details: response.error.description
  });
  
  // 记录请求详情
  console.log('Request details:', {
    url: $node["HTTP Request"].json.url,
    method: $node["HTTP Request"].json.method,
    headers: $node["HTTP Request"].json.headers
  });
}

// 3. 测试API连接性
// 使用简单的GET请求测试基础连接
GET https://httpbin.org/status/200

3. 表达式语法调试

问题:表达式计算结果不符合预期

调试技巧

// 1. 分步调试复杂表达式
// 错误的复杂表达式
{{ $json.orders.filter(o => o.status === 'paid').reduce((sum, o) => sum + o.amount, 0) }}

// 分步调试
// Step 1: 检查原始数据
"debug_orders_raw": "{{ $json.orders }}"

// Step 2: 检查过滤结果  
"debug_paid_orders": "{{ $json.orders.filter(o => o.status === 'paid') }}"

// Step 3: 检查最终计算
"debug_total_amount": "{{ $json.orders.filter(o => o.status === 'paid').reduce((sum, o) => sum + o.amount, 0) }}"

// 2. 使用 Function 节点验证逻辑
const orders = $json.orders;
console.log('Original orders:', orders);

const paidOrders = orders.filter(o => o.status === 'paid');
console.log('Paid orders:', paidOrders);

const totalAmount = paidOrders.reduce((sum, o) => sum + o.amount, 0);
console.log('Total amount:', totalAmount);

return [{ json: { totalAmount } }];

4. 条件逻辑调试

问题:IF 节点条件判断错误

调试方法

// 1. 详细记录条件判断过程
// 在 Function 节点中验证条件
const data = $json;
const conditions = {
  ageCheck: data.age >= 18,
  emailCheck: data.email && data.email.includes('@'),
  statusCheck: data.status === 'active',
  scoreCheck: data.score > 80
};

console.log('Condition checks:', conditions);
console.log('Final result:', Object.values(conditions).every(Boolean));

// 2. 类型检查
console.log('Data types:', {
  age: typeof data.age,
  email: typeof data.email,
  status: typeof data.status,
  score: typeof data.score
});

// 3. 边界值测试
const testCases = [
  { age: 17, expected: false },
  { age: 18, expected: true },
  { age: null, expected: false }
];

testCases.forEach(test => {
  const result = test.age >= 18;
  console.log(`Age ${test.age}: ${result} (expected: ${test.expected})`);
});

🧪 测试策略

1. 单元测试(节点级别)

为每个关键节点创建测试:

// Function 节点:数据验证测试
function testDataValidation() {
  const testData = [
    { email: '[email protected]', expected: true },
    { email: 'invalid-email', expected: false },
    { email: '', expected: false },
    { email: null, expected: false }
  ];
  
  testData.forEach(test => {
    const isValid = validateEmail(test.email);
    console.assert(
      isValid === test.expected,
      `Email validation failed for ${test.email}`
    );
  });
  
  console.log('Email validation tests passed!');
}

function validateEmail(email) {
  if (!email) return false;
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

testDataValidation();

2. 集成测试(工作流级别)

测试完整的工作流程:

// 创建测试工作流
// 1. 准备测试数据
const testWebhookData = {
  orderId: 'TEST-001',
  customerEmail: '[email protected]',
  amount: 299.99,
  items: [
    { productId: 'PROD-001', quantity: 2 }
  ]
};

// 2. 发送测试请求
POST https://your-n8n.com/webhook/test-order
Body: testWebhookData

// 3. 验证输出结果
// 在最后一个节点添加验证
const expectedResults = {
  emailSent: true,
  orderCreated: true,
  inventoryUpdated: true
};

const actualResults = {
  emailSent: $('Send Email').json.messageId ? true : false,
  orderCreated: $('Create Order').json.orderId ? true : false,
  inventoryUpdated: $('Update Inventory').json.updated === 'success'
};

// 对比结果
const testPassed = Object.keys(expectedResults).every(key => 
  expectedResults[key] === actualResults[key]
);

if (!testPassed) {
  console.error('Integration test failed:', {
    expected: expectedResults,
    actual: actualResults
  });
  throw new Error('Integration test failed');
}

console.log('Integration test passed!');

3. 压力测试

测试工作流在高负载下的表现:

// 并发测试脚本
const testConcurrency = async () => {
  const concurrentRequests = 10;
  const promises = [];
  
  for (let i = 0; i < concurrentRequests; i++) {
    const testData = {
      id: `test-${i}`,
      timestamp: new Date().toISOString()
    };
    
    promises.push(
      fetch('https://your-n8n.com/webhook/test', {
        method: 'POST',
        body: JSON.stringify(testData),
        headers: { 'Content-Type': 'application/json' }
      })
    );
  }
  
  const results = await Promise.allSettled(promises);
  const successes = results.filter(r => r.status === 'fulfilled').length;
  
  console.log(`Concurrent test results: ${successes}/${concurrentRequests} succeeded`);
};

📊 监控和日志

1. 自定义日志系统

// Function 节点:结构化日志
class WorkflowLogger {
  constructor(workflowId, nodeId) {
    this.workflowId = workflowId;
    this.nodeId = nodeId;
    this.timestamp = new Date().toISOString();
  }
  
  info(message, data = {}) {
    console.log(JSON.stringify({
      level: 'INFO',
      workflowId: this.workflowId,
      nodeId: this.nodeId,
      timestamp: this.timestamp,
      message,
      data
    }));
  }
  
  error(message, error = {}) {
    console.error(JSON.stringify({
      level: 'ERROR',
      workflowId: this.workflowId,
      nodeId: this.nodeId,
      timestamp: this.timestamp,
      message,
      error: {
        name: error.name,
        message: error.message,
        stack: error.stack
      }
    }));
  }
}

// 使用示例
const logger = new WorkflowLogger('order-processing', 'validate-order');
logger.info('Starting order validation', { orderId: $json.orderId });

try {
  // 业务逻辑
  const result = validateOrder($json);
  logger.info('Order validation completed', { result });
} catch (error) {
  logger.error('Order validation failed', error);
  throw error;
}

2. 性能监控

// Function 节点:性能监控
const performanceMonitor = {
  startTime: Date.now(),
  
  start(operation) {
    this[`${operation}_start`] = Date.now();
  },
  
  end(operation) {
    const duration = Date.now() - this[`${operation}_start`];
    console.log(`Performance: ${operation} took ${duration}ms`);
    return duration;
  },
  
  getTotalDuration() {
    return Date.now() - this.startTime;
  }
};

// 监控API调用
performanceMonitor.start('api_call');
const apiResponse = await callExternalAPI($json);
performanceMonitor.end('api_call');

// 监控数据处理
performanceMonitor.start('data_processing');
const processedData = processLargeDataset($json);
performanceMonitor.end('data_processing');

console.log(`Total workflow duration: ${performanceMonitor.getTotalDuration()}ms`);

3. 错误追踪

// Function 节点:错误上下文收集
const collectErrorContext = (error, inputData) => {
  const context = {
    error: {
      name: error.name,
      message: error.message,
      stack: error.stack
    },
    environment: {
      nodeEnv: $env.NODE_ENV,
      timestamp: new Date().toISOString(),
      workflowId: $workflow.id,
      executionId: $execution.id
    },
    inputData: {
      itemCount: $input.all().length,
      sampleData: JSON.stringify(inputData).substring(0, 500)
    },
    systemInfo: {
      memoryUsage: process.memoryUsage ? process.memoryUsage() : 'N/A',
      uptime: process.uptime ? process.uptime() : 'N/A'
    }
  };
  
  return context;
};

// 使用示例
try {
  // 业务逻辑
  const result = processData($json);
} catch (error) {
  const errorContext = collectErrorContext(error, $json);
  
  // 发送错误报告
  await sendErrorReport(errorContext);
  
  // 重新抛出错误
  throw error;
}

🔧 调试工具和技巧

1. 数据检查器

// Function 节点:通用数据检查器
const dataInspector = (data, label = 'Data') => {
  console.log(`\n=== ${label} Inspector ===`);
  console.log('Type:', typeof data);
  console.log('Constructor:', data?.constructor?.name);
  
  if (Array.isArray(data)) {
    console.log('Array length:', data.length);
    console.log('First item:', data[0]);
    console.log('Sample items:', data.slice(0, 3));
  } else if (typeof data === 'object' && data !== null) {
    console.log('Object keys:', Object.keys(data));
    console.log('Object values preview:', JSON.stringify(data, null, 2).substring(0, 200));
  } else {
    console.log('Value:', data);
  }
  
  console.log('=== End Inspector ===\n');
  return data;
};

// 在管道中使用
const inputData = dataInspector($json, 'Input Data');
const processedData = processData(inputData);
const finalData = dataInspector(processedData, 'Processed Data');

2. 断点调试

// Function 节点:条件断点
const debugBreakpoint = (condition, data, label) => {
  if (condition) {
    console.log(`\n🔴 BREAKPOINT: ${label}`);
    console.log('Condition:', condition);
    console.log('Data at breakpoint:', JSON.stringify(data, null, 2));
    console.log('Call stack available in browser DevTools');
    
    // 在浏览器中触发断点
    debugger;
  }
  return data;
};

// 使用示例
const userData = $json;
debugBreakpoint(
  userData.age < 0,  // 异常条件
  userData,
  'Invalid age detected'
);

3. A/B 测试框架

// Function 节点:A/B测试
const abTestConfig = {
  testName: 'email_template_test',
  variants: {
    A: { template: 'template_a.html', weight: 50 },
    B: { template: 'template_b.html', weight: 50 }
  }
};

const selectVariant = (userId, config) => {
  const hash = hashUserId(userId);
  const totalWeight = Object.values(config.variants)
    .reduce((sum, v) => sum + v.weight, 0);
  
  let currentWeight = 0;
  const targetWeight = (hash % totalWeight);
  
  for (const [variant, data] of Object.entries(config.variants)) {
    currentWeight += data.weight;
    if (targetWeight < currentWeight) {
      return { variant, ...data };
    }
  }
};

const variant = selectVariant($json.userId, abTestConfig);
console.log(`User ${$json.userId} assigned to variant ${variant.variant}`);

// 记录测试参与
await logABTestParticipation($json.userId, abTestConfig.testName, variant.variant);

📋 测试清单

开发阶段测试

  • 每个节点单独测试
  • 数据类型验证
  • 边界条件测试
  • 错误处理验证
  • 表达式语法检查

集成测试

  • 端到端流程测试
  • 多分支路径测试
  • 异常数据处理
  • 外部依赖模拟
  • 性能基准测试

生产前测试

  • 生产数据测试
  • 负载测试
  • 故障恢复测试
  • 监控告警测试
  • 备份恢复测试

🎯 最佳实践

1. 测试数据管理

// 创建可重用的测试数据集
const testDataSets = {
  validUser: {
    id: 'test-001',
    email: '[email protected]',
    age: 25,
    status: 'active'
  },
  invalidUser: {
    id: '',
    email: 'invalid-email',
    age: -1,
    status: 'unknown'
  },
  edgeCaseUser: {
    id: 'test-999',
    email: '[email protected]',
    age: 0,
    status: null
  }
};

2. 环境隔离

// 使用环境变量控制测试行为
const isTestEnvironment = $env.NODE_ENV === 'test';
const isDevelopment = $env.NODE_ENV === 'development';

if (isTestEnvironment) {
  // 使用模拟API
  apiUrl = 'http://localhost:3000/mock-api';
} else {
  // 使用真实API
  apiUrl = $env.PRODUCTION_API_URL;
}

3. 自动化测试

// 在工作流中集成自动化测试
const runAutomatedTests = async () => {
  const testSuite = [
    () => testEmailValidation(),
    () => testDataTransformation(),
    () => testAPIIntegration()
  ];
  
  const results = [];
  for (const test of testSuite) {
    try {
      await test();
      results.push({ status: 'passed', test: test.name });
    } catch (error) {
      results.push({ status: 'failed', test: test.name, error: error.message });
    }
  }
  
  // 发送测试报告
  await sendTestReport(results);
  
  return results;
};

🚀 下一步学习

掌握调试和测试后,继续深入学习:

  1. 条件逻辑 - 构建智能工作流
  2. 错误处理 - 提高系统稳定性
  3. 最佳实践 - 专业工作流设计

良好的调试和测试习惯是构建可靠自动化系统的基石。通过系统性的测试和细致的调试,你能确保工作流在各种情况下都能稳定运行!