Event Sequence Assertions
After appending events through an EventScenario, you often need to verify what ended up in the event sequence itself — not just the result of the append call. The Cratis.Chronicle.Testing package provides Should* extension methods on IEventSequence and IEventLog for these assertions, as well as Should* extension methods on AppendedEventWithResult for asserting on collected events.
Event sequence assertion reference
Section titled “Event sequence assertion reference”These methods are available on any IEventSequence or IEventLog instance, including scenario.EventLog and scenario.EventSequence.
| Method | Asserts |
|---|---|
ShouldHaveTailSequenceNumber(expected) | Tail sequence number matches the expected value |
ShouldHaveAppendedEvent<TEvent>() | At least one event of the given type exists anywhere in the sequence |
ShouldHaveAppendedEvent<TEvent>(validator) | At least one event of the given type exists and passes the validator |
ShouldHaveAppendedEvent<TEvent>(predicate) | At least one event of the given type matches the predicate |
ShouldHaveAppendedEvent<TEvent>(eventSourceId) | At least one event of the given type exists for the event source |
ShouldHaveAppendedEvent<TEvent>(eventSourceId, validator) | At least one event of the given type exists for the event source and passes the validator |
ShouldHaveAppendedEvent<TEvent>(eventSourceId, predicate) | At least one event of the given type matches the predicate for the event source |
ShouldHaveAppendedEvent<TEvent>(sequenceNumber) | An event of the given type exists at the sequence number |
ShouldHaveAppendedEvent<TEvent>(sequenceNumber, validator) | An event of the given type exists at the sequence number and passes the validator |
ShouldHaveAppendedEvent<TEvent>(sequenceNumber, predicate) | An event of the given type at the sequence number matches the predicate |
ShouldHaveAppendedEvent<TEvent>(sequenceNumber, eventSourceId, validator) | An event of the given type exists at the sequence number for the given event source and passes the validator |
ShouldHaveAppendedEvent<TEvent>(sequenceNumber, eventSourceId, predicate) | An event of the given type at the sequence number for the given event source matches the predicate |
All methods are async and return Task. They throw EventSequenceAssertionException on failure with a descriptive message.
Verifying the tail sequence number
Section titled “Verifying the tail sequence number”The tail sequence number is the sequence number of the last event appended to the sequence. Use ShouldHaveTailSequenceNumber to verify the expected number of events were appended:
using Cratis.Chronicle.Events;using Cratis.Chronicle.Testing.EventSequences;
[EventType]public record TestingSeqAssertAuthorRegistered(string Name);
[EventType]public record TestingSeqAssertBookAdded(string Title);
public static class TestingSeqAssertTailSequenceNumber{ public static async Task Run() { var scenario = new EventScenario(); var authorId = EventSourceId.New();
await scenario.EventLog.Append(authorId, new TestingSeqAssertAuthorRegistered("Jane Smith")); await scenario.EventLog.Append(authorId, new TestingSeqAssertBookAdded("Clean Code"));
await scenario.EventLog.ShouldHaveTailSequenceNumber(1); }}import io.cratis.chronicle.events.EventTypeimport io.cratis.chronicle.testing.EventScenarioimport kotlinx.coroutines.runBlockingimport org.junit.jupiter.api.Assertions.assertEqualsimport org.junit.jupiter.api.Test
@EventTypedata class TestingSeqTailAuthorRegistered(val name: String)
@EventTypedata class TestingSeqTailBookAdded(val title: String)
class TailSequenceNumberTests {
@Test fun `the tail sequence number is the position of the last event appended`() = runBlocking { val scenario = EventScenario() val authorId = "author-1"
scenario.eventLog.append(authorId, TestingSeqTailAuthorRegistered("Jane Smith")) scenario.eventLog.append(authorId, TestingSeqTailBookAdded("Clean Code"))
assertEquals(1L, scenario.eventLog.getTailSequenceNumber().value) }}import io.cratis.chronicle.events.EventType;import io.cratis.chronicle.java.BlockingEventSequence;import io.cratis.chronicle.testing.EventScenario;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class TestingEventsEventSequenceAssertionsTailSequenceNumber {
@EventType record AuthorRegistered(String name) { }
@EventType record BookAdded(String title) { }
@Test void theTailSequenceNumberIsThePositionOfTheLastEventAppended() { var scenario = new EventScenario("testing", "default"); var eventLog = new BlockingEventSequence(scenario.getEventSequence()); var authorId = "author-1";
eventLog.append(authorId, new AuthorRegistered("Jane Smith")); eventLog.append(authorId, new BookAdded("Clean Code"));
assertEquals(1L, eventLog.getTailSequenceNumber()); }}Elixir does not support this workflow yet.TypeScript does not support this workflow yet.Sequence numbers are zero-based, so the first event has sequence number 0 and the second has 1. The special value EventSequenceNumber.Unavailable indicates no events have been appended.
Verifying an appended event by type
Section titled “Verifying an appended event by type”Use ShouldHaveAppendedEvent<TEvent> without a sequence number to verify that at least one event of the expected type was appended anywhere in the sequence:
using Cratis.Chronicle.Events;using Cratis.Chronicle.Testing.EventSequences;
public static class TestingSeqAssertAppendedEventByType{ public static async Task Run() { var scenario = new EventScenario(); var authorId = EventSourceId.New();
await scenario.EventLog.Append(authorId, new TestingSeqAssertAuthorRegistered("Jane Smith")); await scenario.EventLog.Append(authorId, new TestingSeqAssertBookAdded("Clean Code"));
await scenario.EventLog.ShouldHaveAppendedEvent<TestingSeqAssertAuthorRegistered>(); await scenario.EventLog.ShouldHaveAppendedEvent<TestingSeqAssertBookAdded>(); }}import io.cratis.chronicle.events.EventTypeimport io.cratis.chronicle.testing.EventScenarioimport io.cratis.chronicle.testing.shouldHaveAppendedimport kotlinx.coroutines.runBlockingimport org.junit.jupiter.api.Test
@EventTypedata class TestingSeqByTypeAuthorRegistered(val name: String)
@EventTypedata class TestingSeqByTypeBookAdded(val title: String)
class AppendedEventByTypeTests {
@Test fun `at least one event of a type was appended somewhere in the sequence`() = runBlocking { val scenario = EventScenario() val authorId = "author-1"
scenario.eventLog.append(authorId, TestingSeqByTypeAuthorRegistered("Jane Smith")) scenario.eventLog.append(authorId, TestingSeqByTypeBookAdded("Clean Code"))
scenario.shouldHaveAppended<TestingSeqByTypeAuthorRegistered>() scenario.shouldHaveAppended<TestingSeqByTypeBookAdded>() }}import io.cratis.chronicle.events.EventType;import io.cratis.chronicle.java.BlockingEventSequence;import io.cratis.chronicle.testing.EventScenario;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertFalse;
class TestingEventsEventSequenceAssertionsAppendedEventByType {
@EventType record AuthorRegistered(String name) { }
@EventType record BookAdded(String title) { }
@Test void atLeastOneEventOfATypeWasAppendedSomewhereInTheSequence() { var scenario = new EventScenario("testing", "default"); var eventLog = new BlockingEventSequence(scenario.getEventSequence()); var authorId = "author-1";
eventLog.append(authorId, new AuthorRegistered("Jane Smith")); eventLog.append(authorId, new BookAdded("Clean Code"));
assertFalse(eventLog.getForEventSourceIdAndEventTypes(authorId, AuthorRegistered.class).isEmpty()); assertFalse(eventLog.getForEventSourceIdAndEventTypes(authorId, BookAdded.class).isEmpty()); }}Elixir does not support this workflow yet.TypeScript does not support this workflow yet.When you know the exact position, pass a sequence number to assert at a specific location:
using Cratis.Chronicle.Events;using Cratis.Chronicle.Testing.EventSequences;
public static class TestingSeqAssertAppendedEventAtPosition{ public static async Task Run(EventScenario scenario) { await scenario.EventLog.ShouldHaveAppendedEvent<TestingSeqAssertAuthorRegistered>(0); await scenario.EventLog.ShouldHaveAppendedEvent<TestingSeqAssertBookAdded>(1); }}import io.cratis.chronicle.events.EventTypeimport io.cratis.chronicle.json.chronicleGsonimport io.cratis.chronicle.testing.EventScenarioimport kotlinx.coroutines.runBlockingimport org.junit.jupiter.api.Assertions.assertEqualsimport org.junit.jupiter.api.Test
@EventTypedata class TestingSeqAtPositionAuthorRegistered(val name: String)
@EventTypedata class TestingSeqAtPositionBookAdded(val title: String)
class AppendedEventAtPositionTests {
@Test fun `an event exists at a specific position in the sequence`() = runBlocking { val scenario = EventScenario() val authorId = "author-1"
scenario.eventLog.append(authorId, TestingSeqAtPositionAuthorRegistered("Jane Smith")) scenario.eventLog.append(authorId, TestingSeqAtPositionBookAdded("Clean Code"))
val events = scenario.eventLog.events val author = chronicleGson.fromJson(events[0].content, TestingSeqAtPositionAuthorRegistered::class.java) val book = chronicleGson.fromJson(events[1].content, TestingSeqAtPositionBookAdded::class.java)
assertEquals("Jane Smith", author.name) assertEquals("Clean Code", book.title) }}import com.google.gson.Gson;
import io.cratis.chronicle.events.EventType;import io.cratis.chronicle.java.BlockingEventSequence;import io.cratis.chronicle.testing.EventScenario;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class TestingEventsEventSequenceAssertionsAppendedEventAtPosition {
@EventType record AuthorRegistered(String name) { }
@EventType record BookAdded(String title) { }
@Test void anEventExistsAtASpecificPositionInTheSequence() { var scenario = new EventScenario("testing", "default"); var eventLog = new BlockingEventSequence(scenario.getEventSequence()); var authorId = "author-1"; var gson = new Gson();
eventLog.append(authorId, new AuthorRegistered("Jane Smith")); eventLog.append(authorId, new BookAdded("Clean Code"));
var events = scenario.getEventLog().getEvents(); var author = gson.fromJson(events.get(0).getContent(), AuthorRegistered.class); var book = gson.fromJson(events.get(1).getContent(), BookAdded.class);
assertEquals("Jane Smith", author.name()); assertEquals("Clean Code", book.title()); }}Elixir does not support this workflow yet.TypeScript does not support this workflow yet.Verifying event content
Section titled “Verifying event content”Pass a validator action to inspect the event content. The assertion fails if the event is not of the expected type or if the validator throws:
using Cratis.Chronicle.Events;using Cratis.Chronicle.Testing.EventSequences;using Cratis.Specifications;
public static class TestingSeqAssertValidator{ public static async Task Run() { var scenario = new EventScenario(); var authorId = EventSourceId.New();
await scenario.EventLog.Append(authorId, new TestingSeqAssertAuthorRegistered("Jane Smith"));
await scenario.EventLog.ShouldHaveAppendedEvent<TestingSeqAssertAuthorRegistered>(0, author => author.Name.ShouldEqual("Jane Smith")); }}import io.cratis.chronicle.events.EventTypeimport io.cratis.chronicle.json.chronicleGsonimport io.cratis.chronicle.testing.EventScenarioimport kotlinx.coroutines.runBlockingimport org.junit.jupiter.api.Assertions.assertEqualsimport org.junit.jupiter.api.Test
@EventTypedata class TestingSeqValidatorAuthorRegistered(val name: String)
class ValidatorTests {
@Test fun `the event at a known position carries the expected content`() = runBlocking { val scenario = EventScenario()
scenario.eventLog.append("author-1", TestingSeqValidatorAuthorRegistered("Jane Smith"))
val author = chronicleGson.fromJson(scenario.eventLog.events[0].content, TestingSeqValidatorAuthorRegistered::class.java) assertEquals("Jane Smith", author.name) }}import com.google.gson.Gson;
import io.cratis.chronicle.events.EventType;import io.cratis.chronicle.java.BlockingEventSequence;import io.cratis.chronicle.testing.EventScenario;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class TestingEventsEventSequenceAssertionsValidator {
@EventType record AuthorRegistered(String name) { }
@Test void theEventAtAKnownPositionCarriesTheExpectedContent() { var scenario = new EventScenario("testing", "default"); var eventLog = new BlockingEventSequence(scenario.getEventSequence()); var gson = new Gson();
eventLog.append("author-1", new AuthorRegistered("Jane Smith"));
var author = gson.fromJson(scenario.getEventLog().getEvents().get(0).getContent(), AuthorRegistered.class);
assertEquals("Jane Smith", author.name()); }}Elixir does not support this workflow yet.TypeScript does not support this workflow yet.Without a sequence number, the validator runs against the first event of the matching type:
using Cratis.Chronicle.Testing.EventSequences;using Cratis.Specifications;
public static class TestingSeqAssertValidatorNoSequence{ public static Task Run(EventScenario scenario) => scenario.EventLog.ShouldHaveAppendedEvent<TestingSeqAssertAuthorRegistered>(author => author.Name.ShouldEqual("Jane Smith"));}import io.cratis.chronicle.events.EventTypeimport io.cratis.chronicle.testing.EventScenarioimport io.cratis.chronicle.testing.shouldHaveAppendedimport kotlinx.coroutines.runBlockingimport org.junit.jupiter.api.Assertions.assertEqualsimport org.junit.jupiter.api.Test
@EventTypedata class TestingSeqValidatorNoSeqAuthorRegistered(val name: String)
class ValidatorNoSequenceTests {
@Test fun `the first matching event anywhere in the sequence carries the expected content`() = runBlocking { val scenario = EventScenario()
scenario.eventLog.append("author-1", TestingSeqValidatorNoSeqAuthorRegistered("Jane Smith"))
val author = scenario.shouldHaveAppended<TestingSeqValidatorNoSeqAuthorRegistered> { it.name == "Jane Smith" } assertEquals("Jane Smith", author.name) }}import com.google.gson.Gson;
import io.cratis.chronicle.events.EventType;import io.cratis.chronicle.java.BlockingEventSequence;import io.cratis.chronicle.testing.EventScenario;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class TestingEventsEventSequenceAssertionsValidatorNoSequence {
@EventType record AuthorRegistered(String name) { }
@Test void theFirstMatchingEventAnywhereInTheSequenceCarriesTheExpectedContent() { var scenario = new EventScenario("testing", "default"); var eventLog = new BlockingEventSequence(scenario.getEventSequence()); var gson = new Gson();
eventLog.append("author-1", new AuthorRegistered("Jane Smith"));
var author = gson.fromJson(scenario.getEventLog().getEvents().get(0).getContent(), AuthorRegistered.class);
assertEquals("Jane Smith", author.name()); }}Elixir does not support this workflow yet.TypeScript does not support this workflow yet.Verifying with a predicate
Section titled “Verifying with a predicate”Pass a Func<TEvent, bool> predicate when you only need to check whether the event satisfies a condition. The assertion fails if no event of the expected type returns true from the predicate:
using Cratis.Chronicle.Events;using Cratis.Chronicle.Testing.EventSequences;
public static class TestingSeqAssertPredicate{ public static async Task Run() { var scenario = new EventScenario(); var authorId = EventSourceId.New();
await scenario.EventLog.Append(authorId, new TestingSeqAssertAuthorRegistered("Jane Smith"));
// Without sequence number — finds any matching event await scenario.EventLog.ShouldHaveAppendedEvent<TestingSeqAssertAuthorRegistered>( author => author.Name == "Jane Smith");
// At a specific sequence number await scenario.EventLog.ShouldHaveAppendedEvent<TestingSeqAssertAuthorRegistered>(0, author => author.Name == "Jane Smith"); }}import io.cratis.chronicle.events.EventTypeimport io.cratis.chronicle.testing.EventScenarioimport io.cratis.chronicle.testing.shouldHaveAppendedimport kotlinx.coroutines.runBlockingimport org.junit.jupiter.api.Test
@EventTypedata class TestingSeqPredicateAuthorRegistered(val name: String)
class PredicateTests {
@Test fun `an appended event satisfies a condition`() = runBlocking { val scenario = EventScenario()
scenario.eventLog.append("author-1", TestingSeqPredicateAuthorRegistered("Jane Smith"))
scenario.shouldHaveAppended<TestingSeqPredicateAuthorRegistered> { it.name == "Jane Smith" } }}import com.google.gson.Gson;
import io.cratis.chronicle.events.EventType;import io.cratis.chronicle.java.BlockingEventSequence;import io.cratis.chronicle.testing.EventScenario;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
class TestingEventsEventSequenceAssertionsPredicate {
@EventType record AuthorRegistered(String name) { }
@Test void anAppendedEventSatisfiesACondition() { var scenario = new EventScenario("testing", "default"); var eventLog = new BlockingEventSequence(scenario.getEventSequence()); var gson = new Gson();
eventLog.append("author-1", new AuthorRegistered("Jane Smith"));
var matches = scenario.getEventLog().getEvents().stream() .map(appended -> gson.fromJson(appended.getContent(), AuthorRegistered.class)) .anyMatch(author -> author.name().equals("Jane Smith"));
assertTrue(matches); }}Elixir does not support this workflow yet.TypeScript does not support this workflow yet.Verifying event content for a specific event source
Section titled “Verifying event content for a specific event source”When events for multiple event sources exist in the same sequence, filter by event source to avoid ambiguity. All event source overloads support both Action<TEvent> validators and Func<TEvent, bool> predicates:
using Cratis.Chronicle.Events;using Cratis.Chronicle.Testing.EventSequences;using Cratis.Specifications;
public static class TestingSeqAssertByEventSource{ public static async Task Run() { var scenario = new EventScenario(); var author1 = EventSourceId.New(); var author2 = EventSourceId.New();
await scenario.EventLog.Append(author1, new TestingSeqAssertAuthorRegistered("Jane Smith")); await scenario.EventLog.Append(author2, new TestingSeqAssertAuthorRegistered("John Doe"));
// With sequence number and validator await scenario.EventLog.ShouldHaveAppendedEvent<TestingSeqAssertAuthorRegistered>(0, author1, author => author.Name.ShouldEqual("Jane Smith"));
// Without sequence number — finds any matching event for the event source await scenario.EventLog.ShouldHaveAppendedEvent<TestingSeqAssertAuthorRegistered>(author2, author => author.Name.ShouldEqual("John Doe"));
// With a predicate instead of a validator await scenario.EventLog.ShouldHaveAppendedEvent<TestingSeqAssertAuthorRegistered>( author1, author => author.Name == "Jane Smith"); }}import io.cratis.chronicle.events.EventTypeimport io.cratis.chronicle.testing.EventScenarioimport io.cratis.chronicle.testing.shouldHaveAppendedimport kotlinx.coroutines.runBlockingimport org.junit.jupiter.api.Assertions.assertEqualsimport org.junit.jupiter.api.Test
@EventTypedata class TestingSeqByEventSourceAuthorRegistered(val name: String)
class ByEventSourceTests {
@Test fun `an appended event is scoped to its own event source`() = runBlocking { val scenario = EventScenario() val author1 = "author-1" val author2 = "author-2"
scenario.eventLog.append(author1, TestingSeqByEventSourceAuthorRegistered("Jane Smith")) scenario.eventLog.append(author2, TestingSeqByEventSourceAuthorRegistered("John Doe"))
val first = scenario.shouldHaveAppended<TestingSeqByEventSourceAuthorRegistered>(author1) { it.name == "Jane Smith" } val second = scenario.shouldHaveAppended<TestingSeqByEventSourceAuthorRegistered>(author2) { it.name == "John Doe" }
assertEquals("Jane Smith", first.name) assertEquals("John Doe", second.name) }}import com.google.gson.Gson;
import io.cratis.chronicle.events.EventType;import io.cratis.chronicle.java.BlockingEventSequence;import io.cratis.chronicle.testing.EventScenario;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class TestingEventsEventSequenceAssertionsByEventSource {
@EventType record AuthorRegistered(String name) { }
@Test void anAppendedEventIsScopedToItsOwnEventSource() { var scenario = new EventScenario("testing", "default"); var eventLog = new BlockingEventSequence(scenario.getEventSequence()); var author1 = "author-1"; var author2 = "author-2"; var gson = new Gson();
eventLog.append(author1, new AuthorRegistered("Jane Smith")); eventLog.append(author2, new AuthorRegistered("John Doe"));
var first = gson.fromJson( eventLog.getForEventSourceIdAndEventTypes(author1, AuthorRegistered.class).get(0).getContent(), AuthorRegistered.class); var second = gson.fromJson( eventLog.getForEventSourceIdAndEventTypes(author2, AuthorRegistered.class).get(0).getContent(), AuthorRegistered.class);
assertEquals("Jane Smith", first.name()); assertEquals("John Doe", second.name()); }}Elixir does not support this workflow yet.TypeScript does not support this workflow yet.AppendedEventWithResult assertions
Section titled “AppendedEventWithResult assertions”When using IEventAppendCollection to collect events (see Event Append Collection), each captured entry is an AppendedEventWithResult. The testing package provides Should* extensions for asserting directly on these entries.
Result assertions
Section titled “Result assertions”All append result assertions are available directly on AppendedEventWithResult — they delegate to the inner Result:
| Method | Asserts |
|---|---|
ShouldBeSuccessful() | Operation succeeded with no violations or errors |
ShouldBeFailed() | Operation failed (any violation or error) |
ShouldHaveConstraintViolations() | At least one constraint violation is present |
ShouldNotHaveConstraintViolations() | No constraint violations are present |
ShouldHaveConstraintViolationFor(name) | A violation for the named constraint is present |
ShouldHaveConcurrencyViolations() | At least one concurrency violation is present |
ShouldNotHaveConcurrencyViolations() | No concurrency violations are present |
ShouldHaveErrors() | At least one error is present |
ShouldNotHaveErrors() | No errors are present |
Event assertions
Section titled “Event assertions”| Method | Asserts |
|---|---|
ShouldHaveEvent<TEvent>(validate?) | Event content is of the given type; optional validator inspects the content |
ShouldBeForEventSource(eventSourceId) | Event was appended for the given event source |
Example: asserting on a collected event
Section titled “Example: asserting on a collected event”using System.Linq;using Cratis.Chronicle.Events;using Cratis.Chronicle.EventSequences;using Cratis.Chronicle.Testing.EventSequences;using Cratis.Specifications;
public static class TestingSeqAssertAppendedEventWithResult{ public static async Task Run() { var scenario = new EventScenario(); var authorId = EventSourceId.New();
var result = await scenario.EventLog.Append(authorId, new TestingSeqAssertAuthorRegistered("Jane Smith")); var appendedEvents = await scenario.EventLog.GetFromSequenceNumber(EventSequenceNumber.First, authorId); var collected = new AppendedEventWithResult(appendedEvents.Last(), result);
collected.ShouldBeSuccessful(); collected.ShouldHaveEvent<TestingSeqAssertAuthorRegistered>(author => author.Name.ShouldEqual("Jane Smith")); collected.ShouldBeForEventSource(authorId); }}import io.cratis.chronicle.events.EventTypeimport io.cratis.chronicle.eventSequences.AppendedEventWithResultimport io.cratis.chronicle.testing.EventScenarioimport kotlinx.coroutines.runBlockingimport org.junit.jupiter.api.Assertions.assertEqualsimport org.junit.jupiter.api.Assertions.assertTrueimport org.junit.jupiter.api.Test
@EventTypedata class TestingSeqWithResultAuthorRegistered(val name: String)
class AppendedEventWithResultTests {
@Test fun `pairing an appended event with its append result`() = runBlocking { val scenario = EventScenario() val authorId = "author-1" val event = TestingSeqWithResultAuthorRegistered("Jane Smith")
val result = scenario.eventLog.append(authorId, event) val context = scenario.eventLog.events.last().context val collected = AppendedEventWithResult(context, event, result)
assertTrue(collected.result.isSuccess) assertEquals("Jane Smith", (collected.event as TestingSeqWithResultAuthorRegistered).name) assertEquals(authorId, collected.context.eventSourceId) }}import io.cratis.chronicle.events.EventType;import io.cratis.chronicle.eventSequences.AppendedEventWithResult;import io.cratis.chronicle.eventSequences.AppendResult;import io.cratis.chronicle.java.BlockingEventSequence;import io.cratis.chronicle.testing.EventScenario;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;import static org.junit.jupiter.api.Assertions.assertTrue;
class TestingEventsEventSequenceAssertionsAppendedEventWithResult {
@EventType record AuthorRegistered(String name) { }
@Test void pairingAnAppendedEventWithItsAppendResult() { var scenario = new EventScenario("testing", "default"); var eventLog = new BlockingEventSequence(scenario.getEventSequence()); var authorId = "author-1"; var event = new AuthorRegistered("Jane Smith");
AppendResult result = eventLog.append(authorId, event); var events = scenario.getEventLog().getEvents(); var context = events.get(events.size() - 1).getContext(); var collected = new AppendedEventWithResult(context, event, result);
assertTrue(collected.getResult().isSuccess()); assertEquals("Jane Smith", ((AuthorRegistered) collected.getEvent()).name()); assertEquals(authorId, collected.getContext().getEventSourceId()); }}Elixir does not support this workflow yet.TypeScript does not support this workflow yet.Full example
Section titled “Full example”The following test pre-seeds state, appends two events, and then verifies both the tail sequence number and individual event content:
using Cratis.Chronicle.Events;using Cratis.Chronicle.Testing.EventSequences;using Cratis.Specifications;using Xunit;
[EventType]public record TestingSeqAssertLibraryCreated(string Name);
public record TestingSeqAssertAuthorId(Guid Value) : EventSourceId<Guid>(Value){ public static TestingSeqAssertAuthorId New() => new(Guid.NewGuid());}
public class when_registering_an_author_and_adding_a_book{ readonly EventScenario _scenario = new();
[Fact] public async Task should_append_both_events_in_order() { var authorId = TestingSeqAssertAuthorId.New();
await _scenario.Given .ForEventSource(authorId) .Events(new TestingSeqAssertLibraryCreated("Main Library"));
await _scenario.EventLog.Append(authorId, new TestingSeqAssertAuthorRegistered("Jane Smith")); await _scenario.EventLog.Append(authorId, new TestingSeqAssertBookAdded("Clean Code"));
// Tail includes the seeded event (0) plus the two appended events (1, 2) await _scenario.EventLog.ShouldHaveTailSequenceNumber(2);
await _scenario.EventLog.ShouldHaveAppendedEvent<TestingSeqAssertAuthorRegistered>(1, author => author.Name.ShouldEqual("Jane Smith")); await _scenario.EventLog.ShouldHaveAppendedEvent<TestingSeqAssertBookAdded>(2, book => book.Title.ShouldEqual("Clean Code")); }}import io.cratis.chronicle.events.EventTypeimport io.cratis.chronicle.testing.EventScenarioimport io.cratis.chronicle.testing.shouldHaveAppendedimport kotlinx.coroutines.runBlockingimport org.junit.jupiter.api.Assertions.assertEqualsimport org.junit.jupiter.api.Test
@EventTypedata class TestingSeqFullExampleAuthorRegistered(val name: String)
@EventTypedata class TestingSeqFullExampleBookAdded(val title: String)
class RegisteringAnAuthorAndAddingABookTests {
@Test fun `both events land in order`() = runBlocking { val scenario = EventScenario() val authorId = "author-1"
scenario.eventLog.append(authorId, TestingSeqFullExampleAuthorRegistered("Jane Smith")) scenario.eventLog.append(authorId, TestingSeqFullExampleBookAdded("Clean Code"))
assertEquals(1L, scenario.eventLog.getTailSequenceNumber().value)
val author = scenario.shouldHaveAppended<TestingSeqFullExampleAuthorRegistered>(authorId) { it.name == "Jane Smith" } val book = scenario.shouldHaveAppended<TestingSeqFullExampleBookAdded>(authorId) { it.title == "Clean Code" }
assertEquals("Jane Smith", author.name) assertEquals("Clean Code", book.title) }}import com.google.gson.Gson;
import io.cratis.chronicle.events.EventType;import io.cratis.chronicle.java.BlockingEventSequence;import io.cratis.chronicle.testing.EventScenario;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
class TestingEventsEventSequenceAssertionsFullExample {
@EventType record AuthorRegistered(String name) { }
@EventType record BookAdded(String title) { }
@Test void bothEventsLandInOrder() { var scenario = new EventScenario("testing", "default"); var eventLog = new BlockingEventSequence(scenario.getEventSequence()); var authorId = "author-1"; var gson = new Gson();
eventLog.append(authorId, new AuthorRegistered("Jane Smith")); eventLog.append(authorId, new BookAdded("Clean Code"));
assertEquals(1L, eventLog.getTailSequenceNumber());
var events = scenario.getEventLog().getEvents(); var author = gson.fromJson(events.get(0).getContent(), AuthorRegistered.class); var book = gson.fromJson(events.get(1).getContent(), BookAdded.class);
assertEquals("Jane Smith", author.name()); assertEquals("Clean Code", book.title()); }}Elixir does not support this workflow yet.TypeScript does not support this workflow yet.For asserting on the result of an individual append operation, see Append Assertions.