原始事件不会以任何方式更新,而是被视为不可变的。
同时,系统将所有这些事件的副本添加到V2版本中引入的消息日志中。
有关更多信息,请参见MigrationToV2项目中Migrator类中的MigrateEventSourcedAndGeneratePastEventLogs。
重建读模型**V2版本包括对订单和注册限界上下文中读模型定义的几个更改。MigrationToV2项目在订单和注册限界上下文中重新构建会议的读模型和价格订单的读模型。
有关更多信息,请参见本章前面的“从会议管理限界上下文中持久化事件”一节。
对测试的影响在这个过程的这个阶段,测试团队继续扩展验收测试集合。他们还创建了一组测试来验证数据迁移过程。
再说SpecFlow之前,这组SpecFlow测试以两种方式实现:通过自动化web浏览器模拟用户交互,或者直接在MVC控制器上操作。这两种方法都有各自的优缺点,我们在第4章“扩展和增强订单和注册限界上下文”中讨论过。
在与另一位专家讨论了这些测试之后,团队还实现了第三种方法。从领域驱动设计(DDD)方法的角度来看,UI不是领域模型的一部分,核心团队的重点应该是在领域专家的帮助下理解领域,并在领域中实现业务逻辑。UI只是机械部分,用于使用户能够与领域进行交互。因此,验收测试应该包括验证领域模型是否以领域专家期望的方式工作。因此,团队使用SpecFlow创建了一组验收测试,这些测试旨在在不影响系统UI部分的情况下测试领域。
下面的代码示例显示了SelfRegistrationEndToEndWithDomain.feature文件,该文件在Conference.AcceptanceTests项目中的Features\Domain\Registration文件夹里,注意When和Then子句怎么使用命令和事件的。
Gary(CQRS专家)发言:通常,如果您的领域模型只使用聚合,您会期望When子句发送命令,Then子句查看事件或异常。然而,在本例中,领域模型包含一个通过发送命令来响应事件的流程管理器。测试将检查是否发送了所有预期的命令,并引发了所有预期的事件。 Feature: Self Registrant end to end scenario for making a Registration for a Conference site with Domain Commands and Events In order to register for a conference As an Attendee I want to be able to register for the conference, pay for the Registration Order and associate myself with the paid Order automatically Scenario: Make a reservation with the selected Order Items Given the list of the available Order Items for the CQRS summit 2012 conference | seat type | rate | quota | | General admission | $199 | 100 | | CQRS Workshop | $500 | 100 | | Additional cocktail party | $50 | 100 | And the selected Order Items | seat type | quantity | | General admission | 1 | | Additional cocktail party | 1 | When the Registrant proceeds to make the Reservation # command:RegisterToConference Then the command to register the selected Order Items is received # event: OrderPlaced And the event for Order placed is emitted # command: MakeSeatReservation And the command for reserving the selected Seats is received # event: SeatsReserved And the event for reserving the selected Seats is emitted # command: MarkSeatsAsReserved And the command for marking the selected Seats as reserved is received # event: OrderReservationCompleted And the event for completing the Order reservation is emitted # event: OrderTotalsCalculated And the event for calculating the total of $249 is emitted
下面的代码示例显示了feature文件的一些步骤实现。这些步骤使用命令总线发送命令。
[When(@"the Registrant proceed to make the Reservation")] public void WhenTheRegistrantProceedToMakeTheReservation() { registerToConference = ScenarioContext.Current.Get<RegisterToConference>(); var conferenceAlias = ScenarioContext.Current.Get<ConferenceAlias>(); registerToConference.ConferenceId = conferenceAlias.Id; orderId = registerToConference.OrderId; this.commandBus.Send(registerToConference); // Wait for event processing Thread.Sleep(Constants.WaitTimeout); } [Then(@"the command to register the selected Order Items is received")] public void ThenTheCommandToRegisterTheSelectedOrderItemsIsReceived() { var orderRepo = EventSourceHelper.GetRepository<Registration.Order>(); Registration.Order order = orderRepo.Find(orderId); Assert.NotNull(order); Assert.Equal(orderId, order.Id); } [Then(@"the event for Order placed is emitted")] public void ThenTheEventForOrderPlacedIsEmitted() { var orderPlaced = MessageLogHelper.GetEvents<OrderPlaced>(orderId).SingleOrDefault(); Assert.NotNull(orderPlaced); Assert.True(orderPlaced.Seats.All( os => registerToConference.Seats.Count(cs => cs.SeatType == os.SeatType && cs.Quantity == os.Quantity) == 1)); } 在迁移过程中发现的bug当测试团队在迁移之后在系统上运行测试时,我们发现订单和注册限界上下文中座位类型的数量与迁移之前的数量不同。调查揭示了以下原因。