Any Rust-based mock for the AWS SDK?

We're using the new AWS Rust SDK, and we need a way of testing our code. localstack looks promising for end-to-end system tests, but it's not practical for unit testing.

What I want is a Rust crate that lets me spin up an emulator for S3 or SSM, point my AWS code at the emulator's URL, test the code, then tear down the emulator - all in Rust. I'd also want to be able to configure the emulator to simulate errors.

I couldn't find anything like that. Does anyone know of such a thing?

Looking at the API, it seems like most clients have a Client::from_conf_conn() constructor whic lets you provide your own aws_smithy_client::bounds::SmithyConnector implementation, where SmithyConnector is implemented automatically for anything implementing Service<Request<SdkBody>, Response = Response<SdkBody>>.

It'll be pretty clunky, but that gives you a way to mock the underlying requests and inject errors.

Say you working on an application which uses a database and wanted to write unit tests for the application logic. You wouldn't create a temporary database for each test, instead you would abstract out the data access logic into something like a Database trait with a get_user_by_id() method. Then, for the unit tests you pass in a mock implementation instead of the implementation backed by Postgres (or whatever).

That way your tests wouldn't also be testing your migrations, whatever you use for SQL mapping, your database driver, and the underlying database. That's good for both quick feedback (your test suite fails in a couple hundred milliseconds instead of after 10+ seconds) and only testing the code you wrote without needing to mock deep implementation details like Postgres's wire format.

Couldn't you do something similar where you abstract out AWS for your application logic and write unit tests that call mocks, then do your overall end-to-end testing with localstack?

1 Like

Yes, I think you're right. After some discussion on my same question on reddit:
Reddit
I think that the 'mock' approach, using traits, is the best approach.

1 Like

That response from u/mikekchar is exactly what I had in mind, with the exception that I would always implement the HttpBinApi trait on a newtype so I can give it a constructor that is specific to my application (e.g. I might know we always use tokens for auth, so I would add a fn with_api_token(token: &str) -> Result<Self, Error> method to avoid the normal boilerplate).

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.