Announcing Spin Test
Melissa Klein
spin
test
plugin
Today we’re happy to announce the very first alpha release of spin-test
, a plugin for Spin that runs tests written in WebAssembly against a Spin application where all Spin and WASI APIs are configurable mocks.
With spin-test
, you can write test scenarios for your app in any language with WebAssembly component support and mock out all interactions your app has with the outside world without requiring any code changes to the app itself. That means the code you test in development is the exact same code that runs in production.
Note: spin-test
is still under active development and so the details here may have changed since this post was first published. Check the spin-test
repo for the latest information on installation and usage.
Installing the Plugin
To run spin-test
, you’ll first need to install the canary release of the plugin. As spin-test
matures, we’ll be making stable releases.
The following command installs the plugin to work on Linux. If you are using another OS/architecture, please visit the canary release page and choose the appropriate Asset to suit your needs:
spin plugin install -u https://github.com/fermyon/spin-test/releases/download/canary/spin-test.json
This will install the plugin which can be invoked with spin test
.
Writing a test
Next you’ll need a test that spin-test
can run compiled to a WebAssembly component.
There is currently first class support for Rust through the spin-test
Rust SDK, but any language with support for writing WebAssembly components can be used as long as the fermyon:spin-test/test
world is targeted. You can find the definition of this world here.
Here’s an example of a test written in Rust using the spin-test
Rust SDK that tests that the Spin app responds properly when the key-value store has a certain key already set:
use spin_test_sdk::{
bindings::{fermyon::spin_test_virt, wasi},
spin_test,
};
#[spin_test]
fn cache_hit() {
let user_json = r#"{"id":123,"name":"Ryan"}"#;
// Configure the app's 'cache' key-value store
let key_value = spin_test_virt::key_value::Store::open("cache");
// Set a specific key with a specific value
key_value.set("123", user_json.as_bytes());
// Make the request against the Spin app
let request = wasi::http::types::OutgoingRequest::new(wasi::http::types::Headers::new());
request.set_path_with_query(Some("/?user_id=123")).unwrap();
let response = spin_test_sdk::perform_request(request);
// Assert the response status and body
assert_eq!(response.status(), 200);
let body = response.body_as_string().unwrap();
assert_eq!(body, user_json);
// Assert the key-value store was queried
assert_eq!(
key_value.calls(),
vec![spin_test_virt::key_value::Call::Get("123".to_owned())]
);
}
The test above will run inside of WebAssembly. The calls to the key value store and the Spin app itself never leave the WebAssembly sandbox. This means your tests are quick and reproducible as you don’t need to rely on running an actual web server, and you don’t need to ensure any of your app’s dependencies are actually running. Everything your app interacts with is mocked for you.
Configure spin-test
Before we can run the test, we’ll need to tell spin-test
where our test lives and how to build it. We do this from inside our app’s spin.toml
manifest. Let’s imagine our app has a component named “my-component” that we want to test. In the spin.toml
manifest we can add the following configuration:
[component.my-component.tool.spin-test]
# A relative path to where the built test component binary will live.
source = "my-test/target/wasm32-wasi/release/test.wasm"
# A command for building the target component.
build = "cargo component build --release"
# The directory where the `build` command should be run.
dir = "my-test"
Running the test
Finally, we’re ready for our test to be run. We can do this simply by invoking spin-test
from the directory where our Spin application lives:
$ spin-test
running 1 test
test cache-hit ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.46s
Next Steps
Looking for another example? The Fermyon Developer Home has an end-to-end spin-test
example that performs an outgoing HTTP request and asserts the response status.
spin-test
is still in the early days of development, so you’re likely to run into things that don’t quite work yet. We’d love to hear about your experience so we can prioritize which features and bugs to fix first. We’re excited about the future of testing powered by WebAssembly components, and we look forward to hearing about your experiences as we continue the development of spin-test
.