1---
2title: Testing Providers
3description: Exercise a provider's create, update, replace, and delete paths with test.provider and a scratch in-memory stack.
4---
5
6You built a provider — now prove its lifecycle. `test.provider` gives each test a private scratch stack, so create / update / replace / delete runs never touch `.alchemy/` or a shared stage.
7
8Building the provider itself? Start at [Build a custom provider](/infrastructure-as-code/custom-provider).
9
10## Scratch stacks with test.provider
11
12`test.provider(name, (stack) => effect)` builds a **scratch stack** with a private in-memory state store, isolated from `.alchemy/` and from sibling tests. Use it to exercise the create / update / replace / delete paths of a provider:
13
14```typescript
15const { test } = Test.make({ providers: MyProvider.providers() });
16
17test.provider(
18 "create, update, delete",
19 (stack) => Effect.gen(function* () {
20 // create
21 const v1 = yield* stack.deploy(
22 Effect.gen(function* () {
23 return yield* MyResource("Test", { name: "v1" });
24 }),
25 );
26
27 // update — same logical ID, new inputs
28 const v2 = yield* stack.deploy(
29 Effect.gen(function* () {
30 return yield* MyResource("Test", { name: "v2" });
31 }),
32 );
33 expect(v2.id).toBe(v1.id);
34
35 // destroy
36 yield* stack.destroy();
37 }),
38);
39```
40
41For a full walkthrough with a real custom provider, see [Build a custom provider → Test the lifecycle](/infrastructure-as-code/custom-provider#test-the-lifecycle).
42
43## Assert against the real cloud
44
45Inside the test body the configured `providers` Layer is already in scope, so out-of-band SDK calls (`DynamoDB.describeTable`, `stripe.products.retrieve`, …) work without extra setup — assert the cloud actually matches the resource's reported outputs, as in the [Stripe walkthrough](/infrastructure-as-code/custom-provider#test-the-lifecycle).
46
47## Verify replacement
48
49Change a `stables` field (or whatever your `diff` flags as `replace`) between two `stack.deploy` calls with the same logical ID:
50
51```typescript
52expect(v2.id).not.toBe(v1.id);
53```
54
55## Scratch state vs persistent state
56
57| | `test` + `deploy(Stack)` | `test.provider` |
58|---|---|---|
59| State store | `state` option (default `localState()`) | private in-memory, per test |
60| Survives runs | yes (the point) | no |
61| Use case | end-to-end against a real stack | provider unit tests |
62
63For end-to-end tests against a real deployed Stack, see [Testing a Stack](/testing/testing-a-stack).
64
65## Seed pre-existing resources
66
67`test.provider`'s in-memory state is exposed as the `state` field on `ScratchStack` for advanced cases. For simpler seeds, just call `stack.deploy(...)` once with the seed, then again with the actual test inputs — the second call sees the first call's output as existing state.
68
69## Where next
70
71- [Build a custom provider](/infrastructure-as-code/custom-provider) — the provider this page tests, end to end.
72- [Providers](/infrastructure-as-code/provider) — the operation contract under test.
73- [Test harness](/testing/test-harness) — everything `Test.make` returns.
74- [Testing](/testing) — the full harness reference.