Reference
Spring API
The bonsai-spring-boot module. It is small on purpose because most of what you call lives in the generic harness, while this module supplies the parts that need an application context.
@EnableMongoEmulator
The Spring flavour. It has the same name as the plain-JUnit annotation but a different package. Import this one in a @SpringBootTest.
package io.typecheck.bonsai.spring;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@ExtendWith(SharedMongoExtension.class)
@ContextConfiguration(initializers = SharedMongoContextInitializer.class)
public @interface EnableMongoEmulator {
/** The property-side spelling is a database.* entry of bonsai.collections. */
String[] databases() default {};
/** Merged with bonsai.collections. */
String[] collections() default {};
/** If empty, resolution uses spring.mongodb.database, then the URI database, then "test". */
String defaultDatabase() default "";
}The list attributes are merged with the properties of the same name rather than overriding them, so a suite-wide property and a class-specific attribute compose. Full property reference: Configuration.
SpringMongoTestData
Typed seeding: the entity half of the seeding API, which the generic MongoTestData deliberately leaves out because it needs Spring. Entities are written through the application's own MongoConverter, so a seeded document matches what the application itself would have stored.
public final class SpringMongoTestData {
public static void insert(String collection, Object entity);
public static void insertAll(String collection, Object... entities);
public static void insertAll(String collection, Collection<?> entities);
public static void insertAll(String collection, SeedSource source);
public static void insertAll(MultiSeedSource source);
public static Document toDocument(Object entity);
}This is not MongoTemplate.save: no lifecycle events fire, no version field is bumped, and a generated _id is not written back into your object. toDocument(...) exposes the conversion on its own, which is useful for asserting on the exact shape an entity maps to.
insertAll(collection, source) (3.4.0+) is the code-fixture form. This class keeps its own verb, where the generic MongoTestData says seedFrom. Its elements may be entities, mapped through the application's converter like every other method here. An entity type that itself implements SeedSource binds to this overload, not to the Object... varargs one.
insertAll(source), with no collection argument, is the (3.4.0+) multi-collection form: a MultiSeedSource whose map keys name the targets. The entity varargs and collection overloads deliberately refuse a MultiSeedSource (or a SeedSource) passed as data is a fixture object handed to a data path means you wanted it invoked, not stored, so the harness says so rather than writing the fixture object itself.
Resolving a SeedSource
A source named by @MongoSeed(sources = …) is resolved against the test ApplicationContext first, so constructor injection of a Clock, a faker, or your own builders works. The rules, in order:
- Exactly one bean of the type: that bean is used, including one declared by a
@Bean SeedSource x()factory method whose return type is the interface. - Several beans: exactly one must be
@Primary. Otherwise the failure names the candidates; the harness never picks silently. - No bean, but a no-argument constructor: the class is constructed reflectively, exactly as a
placeholdersprovider is. - No bean and no no-argument constructor: an error naming both possibilities. There is deliberately no silent fallback, because a class that clearly expects injection would otherwise be seeded with the wrong
Clock.
Which path was taken (bean or constructed) is named in the DEBUG seed line. Note the scoping consequence: a source is otherwise instantiated fresh on every application, but a singleton bean is by definition one instance and keeps its state across methods. A stateful bean source wants @Scope("prototype").
SpringMongoCollectionReader
Typed reading, through the same converter.
public final class SpringMongoCollectionReader {
public static <T> List<T> readDocuments(String qualifiedOrPlain, Class<T> type);
public static <T> List<T> readDocuments(String qualifiedOrPlain, String filterJson,
Class<T> type);
public static <T> T readSingleDocument(String qualifiedOrPlain, String filterJson,
Class<T> type);
}Passing a null type raises IllegalArgumentException pointing you at MongoCollectionReader.readDocuments(...) for raw documents.
Recording properties
bonsai.record.* (3.4.0+) turns a passthrough run into a fixture generator. the narrative is in Record & replay. These are Spring-only, because passthrough is; set on the generic harness they are a named startup refusal. BonsaiRecordings.verify(Path) byte-verifies a live store against a recording.
| Property | Default | Description |
|---|---|---|
bonsai.record.outputString | — | Enables recording; the artifact root. One FQN-named directory per test class, published atomically under a lockfile. |
bonsai.record.includeString | — | FQN glob restricting which classes are recorded. ? is a literal, not a wildcard. |
bonsai.record.databasesList<String> | — | Explicit database allowlist: records a "complete": true manifest; without it, scope is inferred and the manifest says false. |
bonsai.record.allow-remoteboolean | false | Allows recording against a non-local host. Off by default. |
bonsai.record.max-documentsint | 50000 | Volume cap. Exceeding it is a named refusal, not a truncated artifact. |
Change-stream properties
The experimental change-stream surface (3.4.0+) is behind one flag; with it off the shim is byte-identical to 3.3.0. Full behaviour is on Change streams.
| Property | Default | Description |
|---|---|---|
bonsai.experimental.change-streamsboolean | false | Enables collection.watch() and database.watch(). Off by default, where watch() refuses by name as in 3.4.0. |
bonsai.experimental.change-streams.log-limitint | 10000 | Bounded change-event log retained for resume tokens. History evicted past this limit fails with the history-lost signature. |
SharedMongoContextInitializer
Normally applied by the annotation. It is public and usable directly with @ContextConfiguration(initializers = SharedMongoContextInitializer.class) when you are composing your own test annotation.
public final class SharedMongoContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
/** The bean name the embedded MongoClient is registered under. */
public static final String CLIENT_BEAN_NAME = "sharedMongoTestClient";
public void initialize(ConfigurableApplicationContext applicationContext);
}CLIENT_BEAN_NAME is the name the embedded client is registered under, which is occasionally worth knowing when debugging bean wiring.
SharedMongoExtension
/** Registered by the annotation, so tests never name this class. */
public final class SharedMongoExtension
implements BeforeAllCallback, BeforeEachCallback, AfterEachCallback {
public void beforeAll(ExtensionContext extensionContext);
public void beforeEach(ExtensionContext extensionContext);
public void afterEach(ExtensionContext extensionContext);
}What is not public
Several types you may see named in design documents or stack traces are package-private and are not API. They are listed here so you do not go looking for them:
MongoTestSettings: the property record. Configure through property keys, not through this class; there is no public constant to reference.MongoSchemaandMongoIndexFileLoader: the declared-collections/index model behindbonsai.indexes-file.ApplicationMongoConverter: the lookup that makes typed seeding and reading behave like the application's own writes and reads.SpringMongoSeeder: the Spring-flavoured seeding path.SharedMongoBeanOverridePostProcessor,SharedMongoTestState, andSharedMongoHolder: the override and lifecycle machinery.SharedMongoHolderis public but has no public methods at all.