首页
/ GraphQL Yoga 测试指南:从基础到高级实践

GraphQL Yoga 测试指南:从基础到高级实践

2025-07-07 02:00:47作者:温玫谨Lighthearted

GraphQL Yoga 作为一款现代化的 GraphQL 服务器实现,提供了完善的测试支持,让开发者能够轻松验证 GraphQL API 的正确性。本文将全面介绍如何在 GraphQL Yoga 中进行高效测试,涵盖从基础查询到高级订阅测试的完整方案。

测试基础:内置 HTTP 模拟

GraphQL Yoga 最显著的测试优势在于其内置的 HTTP 请求模拟能力。通过 yoga.fetch 方法,开发者可以像发送真实 HTTP 请求一样测试服务器,而实际上这是完全在内存中模拟的进程内通信,既保证了测试效率又不失真实性。

import { createSchema, createYoga } from 'graphql-yoga'

const schema = createSchema({
  typeDefs: /* GraphQL */ `
    type Query {
      greetings: String!
    }
  `,
  resolvers: {
    Query: {
      greetings: () => 'Hello World!'
    }
  }
})

const yoga = createYoga({ schema })

// 测试查询
const response = await yoga.fetch('http://yoga/graphql', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    query: '{ greetings }'
  })
})

高级测试工具:HTTP 执行器

对于更复杂的场景,特别是处理订阅(Subscription)和增量交付(@defer/@stream)协议时,推荐使用 @graphql-tools/executor-http 提供的 buildHTTPExecutor 工具函数。

安装与基本用法

首先安装必要的依赖:

npm install @graphql-tools/executor-http

然后创建执行器实例:

import { buildHTTPExecutor } from '@graphql-tools/executor-http'

const executor = buildHTTPExecutor({
  fetch: yoga.fetch
})

查询和变更测试

使用执行器测试常规查询和变更操作:

const result = await executor({
  document: parse(/* GraphQL */ `
    query {
      greetings
    }
  `)
})

// 验证单值结果
function assertSingleValue<TValue extends object>(
  value: TValue | AsyncIterable<TValue>
): asserts value is TValue {
  if (Symbol.asyncIterator in value) {
    throw new Error('Expected single value')
  }
}

assertSingleValue(result)
console.assert(result.data?.greetings === 'Hello World!')

订阅测试

订阅测试需要特殊处理,因为订阅返回的是事件流而非单次响应:

function assertStreamValue<TValue extends object>(
  value: TValue | AsyncIterable<TValue>
): asserts value is AsyncIterable<TValue> {
  if (!(Symbol.asyncIterator in value)) {
    throw new Error('Expected stream value')
  }
}

const result = await executor({
  document: parse(/* GraphQL */ `
    subscription {
      counter
    }
  `)
})

assertStreamValue(result)

// 迭代处理订阅事件
let iterationCounter = 0
for await (const value of result) {
  console.assert(value.data?.counter === iterationCounter + 1)
  iterationCounter++
  if (iterationCounter >= 2) break
}

类型安全的测试实践

结合 GraphQL Code Generator 可以实现完全类型安全的测试代码:

import { graphql } from './gql' // 生成的类型

const HelloWorldQuery = graphql(/* GraphQL */ `
  query HelloWorld {
    hello
  }
`)

const result = await executor({
  document: HelloWorldQuery
})

// result.data?.hello 现在是类型安全的

这种方式可以避免拼写错误和类型不匹配问题,显著提高测试代码的可靠性。

高级测试场景

对于需要更精细控制的测试场景,可以直接处理请求体和响应流:

自定义订阅事件处理

function eventStream<TType = unknown>(source: ReadableStream<Uint8Array>) {
  return new Repeater<TType>(async (push, end) => {
    const iterable = source[Symbol.asyncIterator]()
    // 处理流数据...
  })
}

const response = await yoga.fetch('http://yoga/graphql', {
  method: 'POST',
  body: JSON.stringify({
    query: 'subscription { counter }'
  })
})

for await (const executionResult of eventStream(response.body!)) {
  // 处理每个订阅事件
}

测试最佳实践

  1. 隔离测试环境:每个测试用例应该使用独立的 Yoga 实例
  2. 模拟外部依赖:在测试中替换真实的外部服务调用
  3. 验证响应状态:除了数据内容,也要检查 HTTP 状态码
  4. 清理资源:特别是订阅测试,确保正确关闭连接
  5. 组合测试:结合单元测试和集成测试策略

通过以上方法,开发者可以构建全面可靠的 GraphQL API 测试套件,确保应用在各种场景下的稳定性和正确性。GraphQL Yoga 提供的测试工具链让这一过程变得简单而高效。