grpc- mock- 服务器
一个轻量级,TypeScript-first gRPC模拟服务器,设计用于测试. 轻松创建模拟 GRPC 服务
.proto没有复杂设置的文件.
* 特性
- 🚀 0 配置 - 几秒钟后开始, 设置最小
- 📦 类型脚本支持 - 使用类型脚本构建,包括类型定义
- 🔧 弹性 - 支持具有交叉包装进口的单一和多原型文件
- 🧪 试验友好 - 适合单位和综合测试
- 🎯 简单 API - 干净、直观的界面
- 🔄 自动/等待 - 基于现代承诺的API
* 安装
npm install @alenon/grpc-mock-server
或用纱线:
yarn add @alenon/grpc-mock-server
QQ 快速启动
仅用几行创建模拟服务器 :
import { GrpcMockServer } from '@alenon/grpc-mock-server';
// Create server instance
const server = new GrpcMockServer();
// Define your service implementations
const implementations = {
GetUser: (call: any, callback: any) => {
callback(null, { name: 'John Doe', id: '123' });
}
};
// Add service from proto file
server.addService(
'./path/to/user.proto',
'user', // package name from proto
'UserService', // service name from proto
implementations
);
// Start the server
await server.start();
console.log(`Server running at: ${server.serverAddress}`);
// Don't forget to stop when done!
await server.stop();
使用实例
Basic 示例 - 单一Proto 文件
这个例子显示了一个单一原型文件最简单的使用案例.
实例。 proto :
syntax = "proto3";
package com.alenon.example;
service ExampleService {
rpc ex1 (ExampleRequest) returns (ExampleResponse) {}
}
message ExampleRequest {
string msg = 1;
}
message ExampleResponse {
string msg = 1;
}
示例:
import { GrpcMockServer } from '@alenon/grpc-mock-server';
import * as grpc from '@grpc/grpc-js';
import * as proto_loader from '@grpc/proto-loader';
import { ProtoUtils } from '@alenon/grpc-mock-server';
async function example() {
const server = new GrpcMockServer();
// Define implementations
const implementations = {
ex1: (call: any, callback: any) => {
console.log('Received:', call.request.msg);
callback(null, { msg: 'Hello from mock server!' });
}
};
// Add service
server.addService(
__dirname + '/example.proto',
'com.alenon.example',
'ExampleService',
implementations
);
// Start server
await server.start();
console.log(`Server listening at: ${server.serverAddress}`);
// Create client and test
const pkgDef = grpc.loadPackageDefinition(
proto_loader.loadSync(__dirname + '/example.proto')
);
const proto = ProtoUtils.getProtoFromPkgDefinition('com.alenon.example', pkgDef);
const client = new proto.ExampleService(
server.serverAddress,
grpc.credentials.createInsecure()
);
// Make request
const response = await new Promise((resolve, reject) => {
client.ex1({ msg: 'Hello!' }, (error: any, response: any) => {
error ? reject(error) : resolve(response);
});
});
console.log('Response:', response);
await server.stop();
}
example().catch(console.error);
高级示例 - 多个Proto 文件
当您从其他软件包导入原生文件时, 请使用一系列原生路径 includeDirs数字 :
用户。 proto :
syntax = "proto3";
package user;
import "address.proto";
message User {
string name = 1;
common.Address address = 2;
}
service UserService {
rpc GetUser (UserRequest) returns (UserResponse);
}
message UserRequest {
string id = 1;
}
message UserResponse {
User user = 1;
}
地址. proto: (中文(简体) )
syntax = "proto3";
package common;
message Address {
string postal_code = 1;
string city = 2;
string country = 3;
}
多实例. ts:
import { GrpcMockServer } from '@alenon/grpc-mock-server';
async function multiProtoExample() {
const server = new GrpcMockServer();
const implementations = {
GetUser: (call: any, callback: any) => {
callback(null, {
user: {
name: 'John Doe',
address: {
postal_code: '12345',
city: 'San Francisco',
country: 'USA'
}
}
});
}
};
// Use array of proto files with options
server.addService(
[
__dirname + '/user.proto',
__dirname + '/address.proto'
],
'user',
'UserService',
implementations,
{
includeDirs: [__dirname], // Required for imports
keepCase: true, // Preserve field names
longs: String, // Convert longs to strings
enums: String, // Convert enums to strings
defaults: true, // Include default values
oneofs: true // Handle oneof fields
}
);
await server.start();
// ... use server ...
await server.stop();
}
测试示例
适合 Jest 或其他测试框架:
import { GrpcMockServer, ProtoUtils } from '@alenon/grpc-mock-server';
import * as grpc from '@grpc/grpc-js';
import * as proto_loader from '@grpc/proto-loader';
describe('ExampleService Tests', () => {
let server: GrpcMockServer;
let client: any;
beforeAll(async () => {
server = new GrpcMockServer();
server.addService(
__dirname + '/example.proto',
'com.alenon.example',
'ExampleService',
{
ex1: (call: any, callback: any) => {
callback(null, { msg: 'Test response' });
}
}
);
await server.start();
// Setup client
const pkgDef = grpc.loadPackageDefinition(
proto_loader.loadSync(__dirname + '/example.proto')
);
const proto = ProtoUtils.getProtoFromPkgDefinition('com.alenon.example', pkgDef);
client = new proto.ExampleService(
server.serverAddress,
grpc.credentials.createInsecure()
);
});
afterAll(async () => {
await server.stop();
});
it('should return response data', async () => {
const response = await new Promise((resolve, reject) => {
client.ex1({ msg: 'Test request' }, (error: any, response: any) => {
error ? reject(error) : resolve(response);
});
});
expect(response.msg).toBe('Test response');
});
});
API 参考
GrpcMockServer
用于创建和管理模拟 gRPC 服务器的主类.
构造器
new GrpcMockServer(serverAddress?: string)
serverAddress(可选) : 格式服务器地址host:port默认 :'127.0.0.1:50777'
方法
addService(protoPath, pkgName, serviceName, implementations, protoLoadOptions?)
向模拟服务器添加 gRPC 服务 .
参数:
protoPath数字 :string | string[]- 原始文件路径。 导入的多个文件使用数组 .pkgName数字 :string- 您定义的软件包名称.proto文档.serviceName数字 :string- 您定义的服务名称.proto文档.implementations数字 :object- 将RPC方法名称映射到其执行中.- 每项执行都是一项职能:
(call: any, callback: any) => void - 打电话
callback(null, response)成绩 - 打电话
callback(error)错误
- 每项执行都是一项职能:
protoLoadOptions(可选)@grpc/proto-loader。共同选项:includeDirs数字 :string[]- 搜索导入原生文件的目录keepCase数字 :boolean- 保留字段名外壳( 默认 ):false(中文(简体) )longs数字 :Function- 如何处理长值(例如,String(中文(简体) )enums数字 :Function- 如何处理enum值(例如,String(中文(简体) )defaults数字 :boolean- 包含默认值( 默认值 :false(中文(简体) )oneofs数字 :boolean- 处理一个字段(默认:false(中文(简体) )
回返情况: GrpcMockServer (用于方法链)
start()
启动模拟服务器.
回返情况: Promise<GrpcMockServer>
stop()
优雅地停止模拟服务器 .
回返情况: Promise<GrpcMockServer>
serverAddress
属性 : string - 服务器在听的地址.
server
属性 : grpc.Server - 访问 GRPC 服务器实例.
常见案件
自定义服务器地址
const server = new GrpcMockServer('localhost:50051');
处理错误
import * as grpc from '@grpc/grpc-js';
const implementations = {
GetUser: (call: any, callback: any) => {
if (!call.request.id) {
callback({ code: grpc.status.INVALID_ARGUMENT, message: 'ID required' });
return;
}
callback(null, { name: 'User', id: call.request.id });
}
};
方法链
await new GrpcMockServer()
.addService(protoPath, pkgName, serviceName, impl1)
.addService(protoPath2, pkgName2, serviceName2, impl2)
.start();
* 解决问题
"好像包的名字错了"
- 校验
pkgName完全匹配package声明.proto文件 - 检查打字和大小写灵敏度
"好像服务名称错了"
- 校验
serviceName匹配您的服务名称.proto文件 - 检查打字和大小写灵敏度
导入带有多个 proto 文件的错误
- 保证
includeDirs包括包含导入原生文件的目录 - 校验原始文件中的导入路径相对于
includeDirs - 使用
keepCase: true如果您的原型使用蛇 case 字段名
已经使用的端口
- 更改服务器地址 :
new GrpcMockServer('127.0.0.1:50778') - 确保停止先前的服务器事件
实例
看看这个 示例目录 用于完整的工作示例:
运行示例 :
npm run example
npm run multi-proto-example
捐款
欢迎捐款! 请随意提交拉力请求.
许可证
麻省理工学院执照 - 看 自由主义 详细文件.
链接
QQ 提示
- 总是打电话
stop()测试后清理资源 - 使用
keepCase: true如果您的原始文件使用蛇 case 命名 - 对于复杂的原始结构,使用
defaults: true财务报告和审定财务报表oneofs: true - 服务器默认使用不安全的证书( 测试完美)
为GRPC测试社区制作