惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
P
Proofpoint News Feed
宝玉的分享
宝玉的分享
人人都是产品经理
人人都是产品经理
博客园_首页
爱范儿
爱范儿
博客园 - 叶小钗
aimingoo的专栏
aimingoo的专栏
S
SegmentFault 最新的问题
MyScale Blog
MyScale Blog
阮一峰的网络日志
阮一峰的网络日志
IT之家
IT之家
Microsoft Security Blog
Microsoft Security Blog
Blog — PlanetScale
Blog — PlanetScale
博客园 - 【当耐特】
Y
Y Combinator Blog
量子位
博客园 - 三生石上(FineUI控件)
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
T
The Blog of Author Tim Ferriss
月光博客
月光博客
有赞技术团队
有赞技术团队
Apple Machine Learning Research
Apple Machine Learning Research
A
About on SuperTechFans

kmcd.dev

Joining Buf Let The Gravity of Ashburn, Virginia The CPU Cost of Protobuf Varints in Go It Beating Go gRPC-Web Should Have Fixed gRPC Making Dynamic Protobuf Fast in Go Proxy, Record, and Mock gRPC APIs with FauxRPC Exploring Protocol Buffers Interactively Introducing ProtoDocs Ghost in the Shell: The Manga Behind the Anime The Hidden Cost of google.protobuf.Value Why Networking Built Its Own Data Modeling Language Zero-Friction Demos with WASM Let's Learn About BGP ConnectRPC: Where is it now? Building APIs with Contracts The Case for Greppable Code Unknown Fields in Protobuf IRC Log: Reactionary Faking protobuf data in Go Y'all are Sleeping on Mise-en-Place IRC Log: Standup 2 HTTP/2 From Scratch: Part 4 IRC Log: rm -rf /var/opt/gitlab/postgresql/data HTTP/2 From Scratch: Part 3 Building a Live BGP Map HTTP/2 From Scratch: Part 2 IRC Log: The Cloud Scale Incident
FauxRPC + Test Containers
2024-10-15 · via kmcd.dev

Testing gRPC services can be tricky. You often need a real server running, which can introduce complexity and slow down your tests. Enter FauxRPC + Testcontainers, and small Go package that simplifies gRPC mocking.

To address challenges with testing while using gRPC services, we can leverage the power of Testcontainers, a library that lets you run throwaway, lightweight instances of common databases, web browsers, or any other application that can run in a Docker container. This allows you to easily integrate these dependencies into your automated tests, providing a consistent and reliable testing environment. By using Testcontainers, you can ensure that your tests are always running against a known and controlled version of your dependencies, avoiding inconsistencies and unexpected behavior while also simplifying test setup/teardown.

While Testcontainers provides the infrastructure, FauxRPC takes care of the mocking itself. FauxRPC is a tool that generates fake gRPC, gRPC-Web, Connect, and REST servers from your Protobuf definitions. By combining it with Testcontainers, you gain a lightweight, isolated environment for testing your gRPC clients without relying on a real server implementation. I’ve made a package to make this simpler using Go but the same could be done for other languages that Testcontainers supports.

Show by Example

1. Setting up the Container

container, err := fauxrpctestcontainers.Run(ctx, "docker.io/sudorandom/fauxrpc:latest")
// ... error handling ...
t.Cleanup(func() { container.Terminate(context.Background()) })

This snippet starts a FauxRPC container using the fauxrpctestcontainers.Run function. The t.Cleanup function ensures the container is terminated after the test, keeping your testing environment clean.

2. Registering the Protobuf Definition

container.MustAddFileDescriptor(ctx, elizav1.File_connectrpc_eliza_v1_eliza_proto)

You register your Protobuf file descriptor with the container. This lets FauxRPC understand the structure of your gRPC service. Now you have a fully functional FauxRPC service that mimics the services in the file descriptor that you gave it. The data is all randomly generated. Now let’s test it a bit.

3. Making gRPC Calls

baseURL := container.MustBaseURL(ctx)
elizaClient := elizav1connect.NewElizaServiceClient(http.DefaultClient, baseURL)
resp, err := elizaClient.Say(ctx, connect.NewRequest(&elizav1.SayRequest{
    Sentence: "testing!",
}))
// ... error handling and assertions ...

This code is getting base URL of the FauxRPC server running in the container and creating a gRPC client (using ConnectRPC). ConnectRPC isn’t a requirement. You can use grpc-go instead. With this client, you can make calls to your gRPC service as you would in a real environment. In this setup, FauxRPC automatically generates responses based on your Protobuf definitions. Here you would normally have some application logic that you want to test so this code might live elsewhere. The randomly generated data might work in a few scenarios but in order to test

4. Defining Stub Responses

For more control over the responses you can define stubs. This allows you to simulate specific scenarios and test how your client handles different responses.

container.MustAddStub(ctx, "connectrpc.eliza.v1.ElizaService/Say", &elizav1.SayResponse{
    Sentence: "I am setting this text!",
})

The power of schemas and mocking

This is basically it. In these examples, I showed how you can:

  1. Stand up an empty FauxRPC service
  2. Populate this server with some Protobuf schema
  3. Connect and use this service
  4. Set stub responses

See full examples in the FauxRPC repo.

Benefits of using FauxRPC+Testcontainers

As demonstrated in the examples above, this approach simplifies gRPC testing by:

  • Simplified Testing: No need to set up a real gRPC server for testing.
  • Isolated Environment: Each test runs in its own container, preventing conflicts and ensuring consistency.
  • Increased Speed: Tests run faster due to the lightweight nature of containers.
  • Improved Control: Stubbing allows you to simulate various scenarios and edge cases.

This package makes gRPC testing in Go much easier and more efficient. Give it a try and let me know what you think!

Alternatives

In Go (and many targets for gRPC), you will get an interface that you can use to generate mock clients. Using the mock client you can usually set responses and assert on data from the request. This is a fair critique, and I feel like this strategy of testing could get you pretty far. However, there are a few reasons that FauxRPC+testcontainers is better.

First, using traditional mocking techniques will prevent you from testing your middleware. Maybe you have middleware that modifies the actual message in certain cases, returns an error, or performs some extra validation or accounting. With the FauxRPC+Testcontainers, you get to exercise the middleware code because you’re talking to a real gRPC service.

In addition to that, maintaining and updating mock clients can be tedious as the gRPC API evolves. FauxRPC avoids this step by being dynamically configurable with protobuf descriptors.

Also, I like that this approach of using FauxRPC is language agnostic. Sure, the little library that makes it easier to use is written specifically in Go, but this code is very trivial to write for other languages.

Ultimately, the choice between mocking strategies depends on your specific needs and priorities.

What’s Next

Excited about the possibilities of FauxRPC Testcontainers? There’s more to come! FauxRPC is still under active development and there’s a lot more on the horizon! Here are a few features I’m exploring:

  • Rules using CEL: Fine-grained control over stub behavior using Common Expression Language (CEL) to define complex matching conditions and response generation logic. This will enable more dynamic and flexible stubbing scenarios. Imaging having a rule saying: req.Name == "Bob" then return a specific stub user.
  • Request Logging: Detailed logging of requests and responses to facilitate debugging and troubleshooting during test execution.
  • Improved documentation: I’m currently working on a refresh of fauxrpc.com that includes these new features.

Have an idea for a new feature or a suggestion for improvement? We’d love to hear from you! Open an issue on the GitHub repository to share your thoughts or contribute to the project.

References