Crates.io | test_executors |
lib.rs | test_executors |
version | 0.3.5 |
created_at | 2024-10-14 19:18:29.840055+00 |
updated_at | 2025-08-17 22:46:40.75516+00 |
description | Simple async executors for testing. |
homepage | https://sealedabstract.com/code/test_executors |
repository | https://github.com/drewcrawford/test_executors |
max_upload_size | |
id | 1408577 |
size | 193,009 |
This crate provides extremely simple, yet useful, async executors. They are primarily useful for writing unit tests without bringing in a full-blown executor such as tokio.
use test_executors::{spin_on, sleep_on};
// Run a simple async function
let result = spin_on(async {
42
});
assert_eq!(result, 42);
// Run an async function that sleeps
let result = sleep_on(async {
// Your async code here
"Hello, async!"
});
assert_eq!(result, "Hello, async!");
The crate provides three main executors:
spin_on
Polls a future in a busy loop on the current thread. Best for CPU-bound tasks or when latency is critical.
When to Use:
Performance Note: This executor will consume 100% CPU while waiting. For I/O-bound tasks or long-running futures, consider using sleep_on
instead.
use test_executors::spin_on;
let result = spin_on(async {
// Simulate some async work
let value = async { 21 }.await;
value * 2
});
assert_eq!(result, 42);
sleep_on
Polls a future on the current thread, sleeping between polls. Best for I/O-bound tasks to avoid burning CPU.
When to Use:
Implementation Details: The executor will properly handle spurious wakeups and re-poll the future as needed. The waker implementation uses a semaphore to signal readiness.
use test_executors::sleep_on;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
struct Counter {
count: u32,
}
impl Future for Counter {
type Output = u32;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.count += 1;
if self.count >= 3 {
Poll::Ready(self.count)
} else {
cx.waker().wake_by_ref();
Poll::Pending
}
}
}
let result = sleep_on(Counter { count: 0 });
assert_eq!(result, 3);
spawn_on
Spawns a future on a new thread, polling it there. Best for fire-and-forget tasks.
This function creates a new OS thread with the given name and runs the future on that thread using sleep_on
. The calling thread returns immediately, making this useful for fire-and-forget tasks.
Requirements:
Send
because it will be moved to another thread'static
because the spawned thread may outlive the calleruse test_executors::spawn_on;
use std::sync::{Arc, Mutex};
use std::time::Duration;
let data = Arc::new(Mutex::new(Vec::new()));
let data_clone = data.clone();
spawn_on("worker", async move {
// Simulate some async work
data_clone.lock().unwrap().push(42);
});
// Give the spawned thread time to complete
std::thread::sleep(Duration::from_millis(50));
// Check the result
assert_eq!(*data.lock().unwrap(), vec![42]);
All executors work as described above on native platforms (Linux, macOS, Windows, etc.).
This crate has special support for wasm32
targets:
async_test
macro automatically adapts to use wasm-bindgen-test
on WASMspawn_local
uses wasm_bindgen_futures::spawn_local
on WASM targetsasync_test
MacroThe async_test
macro allows you to write async tests that work on both native and WASM targets:
use test_executors::async_test;
#[async_test]
async fn my_test() {
let value = async { 42 }.await;
assert_eq!(value, 42);
}
some_executor
This crate implements the some_executor trait for all executors, allowing them to be used in executor-agnostic code:
use test_executors::aruntime::SpinRuntime;
use some_executor::SomeExecutor;
let mut runtime = SpinRuntime::new();
// Use runtime with some_executor traits
The crate also provides utility functions and types:
spawn_local
Platform-aware spawning that works on both native and WASM platforms.
This function automatically selects the appropriate executor based on the target platform:
sleep_on
to run the future on the current threadwasm32
targets: Uses wasm_bindgen_futures::spawn_local
to integrate with the browser's event loopuse test_executors::spawn_local;
spawn_local(async {
// This will run correctly on both native and WASM platforms
println!("Hello from async!");
}, "example_task");
Platform Behavior:
sleep_on
. This blocks until the future completes.poll_once
and poll_once_pin
Poll a future exactly once - useful for testing futures or implementing custom executors.
poll_once
Polls a pinned future exactly once and returns the result.
use test_executors::{poll_once, pend_forever::PendForever};
use std::task::Poll;
let mut future = PendForever;
let result = poll_once(std::pin::Pin::new(&mut future));
assert_eq!(result, Poll::Pending);
poll_once_pin
Polls a future exactly once after pinning it (convenience function that takes ownership).
use test_executors::{poll_once_pin, pend_forever::PendForever};
use std::task::Poll;
let future = PendForever;
let result = poll_once_pin(future);
assert_eq!(result, Poll::Pending);
pend_forever::PendForever
A future that is always pending (useful for testing).
use test_executors::pend_forever::PendForever;
use test_executors::poll_once_pin;
use std::task::Poll;
let future = PendForever;
assert_eq!(poll_once_pin(future), Poll::Pending);