← Back to list

I Mocked Rust Async Services Like a Pro—Here Is What Nobody Told You

The test passed.

Diya Satpute · 2026-05-23 13:28 · 30 claps · 3.3 min read paywalled
#rust #programming #software-development #backend-development #technology
Open on Medium ↗
Wiki topics: 💻 · Programming 🌐 · Web Development

I Mocked Rust Async Services Like a Pro—Here Is What Nobody Told You

The test passed.

Production still exploded.

That was the moment I realized my Rust async mocks were lying to me.

But real async systems are messy. They breathe differently under pressure.

And mocking them correctly is one of the hardest things I have done in Rust.

This article is the stuff I wish somebody had told me earlier.

Not theory.

Not textbook examples.

Just the painful lessons that finally made my async tests trustworthy.

The Mistake That Made My Tests Meaningless

My first mock looked beautiful.

#[async_trait]
trait Mail {
    async fn send(&self, body: String) -> bool;
}

struct FakeMail;
#[async_trait]
impl Mail for FakeMail {
    async fn send(&self, _: String) -> bool {
        true
    }
}

Every test passed.

Every single one.

Then production started failing because the real email service had latency, retries, and connection limits.

My mock had none of that.

It was not simulating behavior.

It was simulating fantasy.

That is when I learned the most dangerous thing about async mocks:

Fast mocks create slow disasters.

Async Bugs Hide in Timing

Synchronous code fails loudly.

Async code fails sideways.

A future gets dropped too early. A timeout races another task. A channel closes one millisecond sooner than expected.

And your mock happily says:

“Everything is fine.”

No. It is not fine.

If your mock responds instantly every time, you are testing a universe that does not exist.

I started adding realistic delay into mocks.

use tokio::time::{sleep, Duration};

struct SlowMail;
#[async_trait]
impl Mail for SlowMail {
    async fn send(&self, _: String) -> bool {
        sleep(Duration::from_millis(300)).await;
        true
    }
}

That single delay exposed race conditions immediately.

Tests that looked “stable” suddenly became flaky.

Good.

Flaky tests are painful.

Fake stability is worse.

The Real Trick: Mock Behavior, Not Responses

This changed everything for me.

Most developers mock outputs.

Experienced Rust developers mock pressure.

Big difference.

Instead of:

return Ok(data)

I started simulating:

  • timeouts
  • slow I/O
  • dropped connections
  • partial failures
  • queue saturation

Because async systems fail through coordination problems.

Not syntax.

Here is the architecture that finally made my tests realistic:

+-------------+
| app service |
+------+------+
       |
       v
+-------------+
| trait layer |
+------+------+
       |
  +----+----+
  |         |
  v         v
mock      real
service   service

Simple.

But the important part was this:

Both implementations behaved emotionally similar under load.

That matters more than matching return types.

The Benchmark That Humbled Me

I once benchmarked two test suites.

The “clean” mocks finished in:

1.2 seconds

The realistic async mocks finished in:

8.9 seconds

Guess which suite found the production bug.

The slower one.

Every time.

Rust developers love speed.

I do too.

But ultra-fast tests can become a trap when async behavior is involved.

You are not testing correctness anymore.

You are testing ideal conditions.

Production is never ideal.

My Favorite Pattern for Async Mocks

Eventually I stopped building “fake objects.”

I started building tiny controllable systems.

This pattern became my default:

use tokio::sync::Mutex;

struct FakeDb {
    fail: Mutex<bool>,
}
impl FakeDb {
    async fn set_fail(&self, v: bool) {
        *self.fail.lock().await = v;
    }
}

Now tests could dynamically change behavior mid-execution.

That unlocked something huge.

I could simulate:

  • service degradation
  • temporary outages
  • recovery
  • unstable infrastructure

Suddenly my tests felt alive.

Not scripted.

Alive.

That is the closest I have come to production realism inside unit tests.

The Part Nobody Admits

Mocking async Rust services is mentally exhausting.

Because you are not mocking data.

You are mocking time.

And time is where distributed systems become dangerous.

One tiny scheduling difference can expose a bug you never imagined.

That is why experienced Rust engineers become obsessed with:

  • cancellation safety
  • backpressure
  • task coordination
  • timeout boundaries
  • ownership across async tasks

The language forces you to think harder.

At first it feels brutal.

Then one day you realize:

Rust is teaching you how real systems actually fail.

That lesson changed the way I write software.

Not just Rust.

Everything.

What Finally Made My Tests Reliable

After months of painful debugging, I settled on a few rules.

I follow them aggressively now.

1. Every important mock gets latency

Even tiny latency.

Especially tiny latency.

2. At least one test must simulate failure

Real systems fail constantly.

Your tests should too.

3. Shared state matters more than fake return values

Async systems are coordination problems.

Model the coordination.

4. If a mock feels “too clean,” it probably is

Trust that instinct.

5. Green tests mean nothing without pressure

This one hurt to learn.

Final Thought

The biggest lie in software testing is not failing tests.

It is passing tests that should have failed.

That is exactly what bad async mocks do.

Rust forced me to stop writing comfortable tests.

And honestly, that made me a much better engineer.

Because production does not care how elegant your mock was.

Production cares whether your system survives reality.


메타데이터
post_id
bc3f0d2f9c65
slug
i-mocked-rust-async-services-like-a-pro-here-is-what-nobody-told-you-bc3f0d2f9c65
url
https://medium.com/@diyasanjaysatpute147/i-mocked-rust-async-services-like-a-pro-here-is-what-nobody-told-you-bc3f0d2f9c65
canonical_url
https://medium.com/@diyasanjaysatpute147/i-mocked-rust-async-services-like-a-pro-here-is-what-nobody-told-you-bc3f0d2f9c65
author_url
https://medium.com/@diyasanjaysatpute147
status
ok
fetched_at
2026-06-09 15:37:30