-
-
Notifications
You must be signed in to change notification settings - Fork 522
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
3496f86
commit 5bce873
Showing
9 changed files
with
791 additions
and
0 deletions.
There are no files selected for viewing
220 changes: 220 additions & 0 deletions
220
...s/EventDrivenArchitecture/Solutions/03-BusinessProcesses/ToDoList/BusinessProcessTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,220 @@ | ||
using Bogus; | ||
using BusinessProcesses.ToDoList.GroupCheckouts; | ||
using BusinessProcesses.ToDoList.GuestStayAccounts; | ||
using BusinessProcesses.Core; | ||
using Xunit; | ||
using Xunit.Abstractions; | ||
using Database = BusinessProcesses.Core.Database; | ||
|
||
namespace BusinessProcesses.ToDoList; | ||
|
||
using static GuestStayAccountEvent; | ||
using static GuestStayAccountCommand; | ||
using static GroupCheckoutCommand; | ||
using static GroupCheckoutsConfig; | ||
using static GuestStayAccountsConfig; | ||
|
||
public class BusinessProcessTests | ||
{ | ||
[Fact] | ||
public async Task GroupCheckoutForMultipleGuestStayWithoutPaymentsAndCharges_ShouldComplete() | ||
{ | ||
// Given; | ||
Guid[] guestStays = [Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid()]; | ||
|
||
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[0], now.AddDays(-1))); | ||
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[1], now.AddDays(-1))); | ||
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[2], now.AddDays(-1))); | ||
publishedMessages.Reset(); | ||
// And | ||
var groupCheckoutId = Guid.NewGuid(); | ||
var clerkId = Guid.NewGuid(); | ||
var command = new InitiateGroupCheckout(groupCheckoutId, clerkId, guestStays, now); | ||
|
||
// When | ||
await groupCheckoutToDoList.InitiateGroupCheckout(command); | ||
|
||
// Then | ||
publishedMessages.ShouldReceiveMessages( | ||
[ | ||
new GroupCheckoutEvent.GroupCheckoutInitiated(groupCheckoutId, clerkId, guestStays, now), | ||
new CheckOutGuest(guestStays[0], now, groupCheckoutId), | ||
new GuestCheckedOut(guestStays[0], now, groupCheckoutId), | ||
new CheckOutGuest(guestStays[1], now, groupCheckoutId), | ||
new GuestCheckedOut(guestStays[1], now, groupCheckoutId), | ||
new CheckOutGuest(guestStays[2], now, groupCheckoutId), | ||
new GuestCheckedOut(guestStays[2], now, groupCheckoutId), | ||
new GroupCheckoutEvent.GroupCheckoutCompleted(groupCheckoutId, guestStays, now), | ||
] | ||
); | ||
} | ||
|
||
[Fact] | ||
public async Task GroupCheckoutForMultipleGuestStayWithAllStaysSettled_ShouldComplete() | ||
{ | ||
// Given; | ||
Guid[] guestStays = [Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid()]; | ||
decimal[] amounts = [generate.Finance.Amount(), generate.Finance.Amount(), generate.Finance.Amount()]; | ||
|
||
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[0], now.AddDays(-1))); | ||
await guestStayFacade.RecordCharge(new RecordCharge(guestStays[0], amounts[0], now.AddHours(-2))); | ||
await guestStayFacade.RecordPayment(new RecordPayment(guestStays[0], amounts[0], now.AddHours(-1))); | ||
|
||
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[1], now.AddDays(-1))); | ||
await guestStayFacade.RecordPayment(new RecordPayment(guestStays[1], amounts[1], now.AddHours(-1))); | ||
await guestStayFacade.RecordCharge(new RecordCharge(guestStays[1], amounts[1], now.AddHours(-2))); | ||
|
||
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[2], now.AddDays(-1))); | ||
await guestStayFacade.RecordCharge(new RecordCharge(guestStays[0], amounts[2], now.AddHours(-2))); | ||
await guestStayFacade.RecordPayment(new RecordPayment(guestStays[0], amounts[2] / 2, now.AddHours(-1))); | ||
await guestStayFacade.RecordPayment(new RecordPayment(guestStays[0], amounts[2] / 2, now.AddHours(-1))); | ||
publishedMessages.Reset(); | ||
// And | ||
var groupCheckoutId = Guid.NewGuid(); | ||
var clerkId = Guid.NewGuid(); | ||
var command = new InitiateGroupCheckout(groupCheckoutId, clerkId, guestStays, now); | ||
|
||
// When | ||
await groupCheckoutToDoList.InitiateGroupCheckout(command); | ||
|
||
// Then | ||
publishedMessages.ShouldReceiveMessages( | ||
[ | ||
new GroupCheckoutEvent.GroupCheckoutInitiated(groupCheckoutId, clerkId, guestStays, now), | ||
new CheckOutGuest(guestStays[0], now, groupCheckoutId), | ||
new GuestCheckedOut(guestStays[0], now, groupCheckoutId), | ||
new CheckOutGuest(guestStays[1], now, groupCheckoutId), | ||
new GuestCheckedOut(guestStays[1], now, groupCheckoutId), | ||
new CheckOutGuest(guestStays[2], now, groupCheckoutId), | ||
new GuestCheckedOut(guestStays[2], now, groupCheckoutId), | ||
new GroupCheckoutEvent.GroupCheckoutCompleted(groupCheckoutId, guestStays, now), | ||
] | ||
); | ||
} | ||
|
||
[Fact] | ||
public async Task GroupCheckoutForMultipleGuestStayWithOneSettledAndRestUnsettled_ShouldFail() | ||
{ | ||
// Given; | ||
Guid[] guestStays = [Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid()]; | ||
decimal[] amounts = [generate.Finance.Amount(), generate.Finance.Amount(), generate.Finance.Amount()]; | ||
|
||
// 🟢 settled | ||
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[0], now.AddDays(-1))); | ||
await guestStayFacade.RecordCharge(new RecordCharge(guestStays[0], amounts[0], now.AddHours(-2))); | ||
await guestStayFacade.RecordPayment(new RecordPayment(guestStays[0], amounts[0], now.AddHours(-1))); | ||
|
||
// 🛑 payment without charge | ||
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[1], now.AddDays(-1))); | ||
await guestStayFacade.RecordPayment(new RecordPayment(guestStays[1], amounts[1], now.AddHours(-1))); | ||
|
||
// 🛑 payment without charge | ||
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[2], now.AddDays(-1))); | ||
await guestStayFacade.RecordCharge(new RecordCharge(guestStays[2], amounts[2], now.AddHours(-2))); | ||
await guestStayFacade.RecordPayment(new RecordPayment(guestStays[2], amounts[2] / 2, now.AddHours(-1))); | ||
publishedMessages.Reset(); | ||
// And | ||
var groupCheckoutId = Guid.NewGuid(); | ||
var clerkId = Guid.NewGuid(); | ||
var command = new InitiateGroupCheckout(groupCheckoutId, clerkId, guestStays, now); | ||
|
||
// When | ||
await groupCheckoutToDoList.InitiateGroupCheckout(command); | ||
|
||
// Then | ||
publishedMessages.ShouldReceiveMessages( | ||
[ | ||
new GroupCheckoutEvent.GroupCheckoutInitiated(groupCheckoutId, clerkId, guestStays, now), | ||
new CheckOutGuest(guestStays[0], now, groupCheckoutId), | ||
new GuestCheckedOut(guestStays[0], now, groupCheckoutId), | ||
new CheckOutGuest(guestStays[1], now, groupCheckoutId), | ||
new GuestCheckOutFailed(guestStays[1], GuestCheckOutFailed.FailureReason.BalanceNotSettled, now, | ||
groupCheckoutId), | ||
new CheckOutGuest(guestStays[2], now, groupCheckoutId), | ||
new GuestCheckOutFailed(guestStays[2], GuestCheckOutFailed.FailureReason.BalanceNotSettled, now, | ||
groupCheckoutId), | ||
new GroupCheckoutEvent.GroupCheckoutFailed( | ||
groupCheckoutId, | ||
[guestStays[0]], | ||
[guestStays[1], guestStays[2]], | ||
now | ||
), | ||
] | ||
); | ||
} | ||
|
||
|
||
[Fact] | ||
public async Task GroupCheckoutForMultipleGuestStayWithAllUnsettled_ShouldFail() | ||
{ | ||
// Given; | ||
Guid[] guestStays = [Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid()]; | ||
decimal[] amounts = [generate.Finance.Amount(), generate.Finance.Amount(), generate.Finance.Amount()]; | ||
|
||
// 🛑 charge without payment | ||
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[0], now.AddDays(-1))); | ||
await guestStayFacade.RecordCharge(new RecordCharge(guestStays[0], amounts[0], now.AddHours(-2))); | ||
|
||
// 🛑 payment without charge | ||
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[1], now.AddDays(-1))); | ||
await guestStayFacade.RecordPayment(new RecordPayment(guestStays[1], amounts[1], now.AddHours(-1))); | ||
|
||
// 🛑 payment without charge | ||
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStays[2], now.AddDays(-1))); | ||
await guestStayFacade.RecordCharge(new RecordCharge(guestStays[2], amounts[2], now.AddHours(-2))); | ||
await guestStayFacade.RecordPayment(new RecordPayment(guestStays[2], amounts[2] / 2, now.AddHours(-1))); | ||
publishedMessages.Reset(); | ||
// And | ||
var groupCheckoutId = Guid.NewGuid(); | ||
var clerkId = Guid.NewGuid(); | ||
var command = new InitiateGroupCheckout(groupCheckoutId, clerkId, guestStays, now); | ||
|
||
// When | ||
await groupCheckoutToDoList.InitiateGroupCheckout(command); | ||
|
||
// Then | ||
publishedMessages.ShouldReceiveMessages( | ||
[ | ||
new GroupCheckoutEvent.GroupCheckoutInitiated(groupCheckoutId, clerkId, guestStays, now), | ||
new CheckOutGuest(guestStays[0], now, groupCheckoutId), | ||
new GuestCheckOutFailed(guestStays[0], GuestCheckOutFailed.FailureReason.BalanceNotSettled, now, | ||
groupCheckoutId), | ||
new CheckOutGuest(guestStays[1], now, groupCheckoutId), | ||
new GuestCheckOutFailed(guestStays[1], GuestCheckOutFailed.FailureReason.BalanceNotSettled, now, | ||
groupCheckoutId), | ||
new CheckOutGuest(guestStays[2], now, groupCheckoutId), | ||
new GuestCheckOutFailed(guestStays[2], GuestCheckOutFailed.FailureReason.BalanceNotSettled, now, | ||
groupCheckoutId), | ||
new GroupCheckoutEvent.GroupCheckoutFailed( | ||
groupCheckoutId, | ||
[], | ||
[guestStays[0], guestStays[1], guestStays[2]], | ||
now | ||
), | ||
] | ||
); | ||
} | ||
|
||
private readonly Database database = new(); | ||
private readonly EventBus eventBus = new(); | ||
private readonly CommandBus commandBus = new(); | ||
private readonly MessageCatcher publishedMessages = new(); | ||
private readonly GuestStayFacade guestStayFacade; | ||
private readonly GroupCheckOutToDoList groupCheckoutToDoList; | ||
private readonly Faker generate = new(); | ||
private readonly DateTimeOffset now = DateTimeOffset.Now; | ||
private readonly ITestOutputHelper testOutputHelper; | ||
|
||
public BusinessProcessTests(ITestOutputHelper testOutputHelper) | ||
{ | ||
this.testOutputHelper = testOutputHelper; | ||
guestStayFacade = new GuestStayFacade(database, eventBus); | ||
groupCheckoutToDoList = new GroupCheckOutToDoList(database, eventBus, commandBus); | ||
|
||
eventBus.Use(publishedMessages.Catch); | ||
commandBus.Use(publishedMessages.Catch); | ||
|
||
ConfigureGroupCheckouts(eventBus, groupCheckoutToDoList); | ||
ConfigureGuestStayAccounts(commandBus, guestStayFacade); | ||
} | ||
} |
148 changes: 148 additions & 0 deletions
148
.../EventDrivenArchitecture/Solutions/03-BusinessProcesses/ToDoList/EntityDefinitionTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
using Bogus; | ||
using BusinessProcesses.ToDoList.GuestStayAccounts; | ||
using BusinessProcesses.Core; | ||
using Xunit; | ||
using Xunit.Abstractions; | ||
using Database = BusinessProcesses.Core.Database; | ||
|
||
namespace BusinessProcesses.ToDoList; | ||
|
||
using static GuestStayAccountEvent; | ||
using static GuestStayAccountCommand; | ||
|
||
public class EntityDefinitionTests | ||
{ | ||
[Fact] | ||
public async Task CheckingInGuest_Succeeds() | ||
{ | ||
// Given | ||
var guestStayId = Guid.NewGuid(); | ||
var command = new CheckInGuest(guestStayId, now); | ||
publishedMessages.Reset(); | ||
|
||
// When | ||
await guestStayFacade.CheckInGuest(command); | ||
|
||
// Then | ||
publishedMessages.ShouldReceiveSingleMessage(new GuestCheckedIn(guestStayId, now)); | ||
} | ||
|
||
[Fact] | ||
public async Task RecordingChargeForCheckedInGuest_Succeeds() | ||
{ | ||
// Given | ||
var guestStayId = Guid.NewGuid(); | ||
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStayId, now.AddDays(-1))); | ||
publishedMessages.Reset(); | ||
// And | ||
var amount = generate.Finance.Amount(); | ||
var command = new RecordCharge(guestStayId, amount, now); | ||
|
||
// When | ||
await guestStayFacade.RecordCharge(command); | ||
|
||
// Then | ||
publishedMessages.ShouldReceiveSingleMessage(new ChargeRecorded(guestStayId, amount, now)); | ||
} | ||
|
||
[Fact] | ||
public async Task RecordingPaymentForCheckedInGuest_Succeeds() | ||
{ | ||
// Given | ||
var guestStayId = Guid.NewGuid(); | ||
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStayId, now.AddDays(-1))); | ||
publishedMessages.Reset(); | ||
// And | ||
var amount = generate.Finance.Amount(); | ||
var command = new RecordPayment(guestStayId, amount, now); | ||
|
||
// When | ||
await guestStayFacade.RecordPayment(command); | ||
|
||
// Then | ||
publishedMessages.ShouldReceiveSingleMessage(new PaymentRecorded(guestStayId, amount, now)); | ||
} | ||
|
||
[Fact] | ||
public async Task RecordingPaymentForCheckedInGuestWithCharge_Succeeds() | ||
{ | ||
// Given | ||
var guestStayId = Guid.NewGuid(); | ||
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStayId, now.AddDays(-1))); | ||
await guestStayFacade.RecordCharge(new RecordCharge(guestStayId, generate.Finance.Amount(), now.AddHours(-1))); | ||
publishedMessages.Reset(); | ||
// And | ||
var amount = generate.Finance.Amount(); | ||
var command = new RecordPayment(guestStayId, amount, now); | ||
|
||
// When | ||
await guestStayFacade.RecordPayment(command); | ||
|
||
// Then | ||
publishedMessages.ShouldReceiveSingleMessage(new PaymentRecorded(guestStayId, amount, now)); | ||
} | ||
|
||
[Fact] | ||
public async Task CheckingOutGuestWithSettledBalance_Succeeds() | ||
{ | ||
// Given | ||
var guestStayId = Guid.NewGuid(); | ||
|
||
var amount = generate.Finance.Amount(); | ||
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStayId, now.AddDays(-1))); | ||
await guestStayFacade.RecordCharge(new RecordCharge(guestStayId, amount, now.AddHours(-2))); | ||
await guestStayFacade.RecordPayment(new RecordPayment(guestStayId, amount, now.AddHours(-1))); | ||
publishedMessages.Reset(); | ||
// And | ||
var command = new CheckOutGuest(guestStayId, now); | ||
|
||
// When | ||
await guestStayFacade.CheckOutGuest(command); | ||
|
||
// Then | ||
publishedMessages.ShouldReceiveSingleMessage(new GuestCheckedOut(guestStayId, now)); | ||
} | ||
|
||
[Fact] | ||
public async Task CheckingOutGuestWithSettledBalance_FailsWithGuestCheckoutFailed() | ||
{ | ||
// Given | ||
var guestStayId = Guid.NewGuid(); | ||
|
||
var amount = generate.Finance.Amount(); | ||
await guestStayFacade.CheckInGuest(new CheckInGuest(guestStayId, now.AddDays(-1))); | ||
await guestStayFacade.RecordCharge(new RecordCharge(guestStayId, amount + 10, now.AddHours(-2))); | ||
await guestStayFacade.RecordPayment(new RecordPayment(guestStayId, amount, now.AddHours(-1))); | ||
publishedMessages.Reset(); | ||
// And | ||
var command = new CheckOutGuest(guestStayId, now); | ||
|
||
// When | ||
try | ||
{ | ||
await guestStayFacade.CheckOutGuest(command); | ||
} | ||
catch (Exception exc) | ||
{ | ||
testOutputHelper.WriteLine(exc.Message); | ||
} | ||
|
||
// Then | ||
publishedMessages.ShouldReceiveSingleMessage(new GuestCheckOutFailed(guestStayId, GuestCheckOutFailed.FailureReason.BalanceNotSettled, now)); | ||
} | ||
|
||
private readonly Database database = new(); | ||
private readonly EventBus eventBus = new(); | ||
private readonly MessageCatcher publishedMessages = new(); | ||
private readonly GuestStayFacade guestStayFacade; | ||
private readonly Faker generate = new(); | ||
private readonly DateTimeOffset now = DateTimeOffset.Now; | ||
private readonly ITestOutputHelper testOutputHelper; | ||
|
||
public EntityDefinitionTests(ITestOutputHelper testOutputHelper) | ||
{ | ||
this.testOutputHelper = testOutputHelper; | ||
guestStayFacade = new GuestStayFacade(database, eventBus); | ||
eventBus.Use(publishedMessages.Catch); | ||
} | ||
} |
Oops, something went wrong.