我有一个小系统,它使用乔纳森·奥利弗( Jonathan )的CommonDomain和EventStore。
如何对聚合根进行单元测试以验证是否引发了正确的事件?
考虑以下聚合根:
public class Subscriber : AggregateBase
{
private Subscriber(Guid id)
{
this.Id = id;
}
private Subscriber(Guid id, string email, DateTimeOffset registeredDate)
: this(id)
{
this.RaiseEvent(new NewSubscriberRegistered(this.Id, email, registeredDate));
}
public string Email{ get; private set; }
public DateTimeOffset RegisteredDate { get; private set; }
public static Subscriber Create(Guid id, string email, DateTimeOffset registeredDate)
{
return new Subscriber(id, email, registeredDate);
}
private void Apply(NewSubscriberRegistered @event)
{
this.Email = @event.Email;
this.RegisteredDate = @event.RegisteredDate;
}
}我想写一个下面的测试:
// Arrange
var id = Guid.NewGuid();
var email = "test@thelightfull.com";
var registeredDate = DateTimeOffset.Now;
// Act
var subscriber = Subscriber.Create(id, email, registeredDate);
// Assert
var eventsRaised = subscriber.GetEvents(); <---- How to get the events?
// Assert that NewSubscriberRegistered event was raised with valid data我可以使用内存持久性和同步分派程序来设置整个EventStore,挂起模拟事件处理程序,并存储任何已发布的事件以进行验证,但这似乎有点过分。
在IRouteEvents中有一个接口CommonDomain。看起来我可以模拟它来直接从AggregateBase获取事件,但是我如何将它实际传递给我的Subscriber类呢?我不想用与测试相关的代码“污染”我的domian。
发布于 2012-11-15 19:00:30
我发现AggregateBase显式地实现了IAggregate接口,它公开了ICollection GetUncommittedEvents();方法。
所以单元测试看起来是这样的:
var eventsRaised = ((IAggregate)subscriber).GetUncommittedEvents();
而且不需要依赖EventStore。
发布于 2014-03-07 17:37:06
我只是用我在不同地方(StackOverflow、有文档地、格雷格·杨的技法演员)收集的代码向上推高了StackOverflow。
它是NEventStore的一个非常基本的实现,它使用CommonDomain重建聚合状态,使用EventSpecification基测试类测试聚合行为。
发布于 2013-01-19 00:42:58
下面是一个相当简单的测试工具,它使用NUnit和ApprovalTests测试CommonDomain聚合根。(ApprovalTests并不是必需的--只是有点让生活变得简单)。
假设1)使用聚合(可能已经在某种状态下设置)以及一系列要应用的“给定”事件实例化夹具。2)然后测试将调用特定的命令处理程序作为TestCommand方法的一部分--当前期望是一个Func,它返回所处理的命令(聚合快照、命令和事件都包含“富”ToString方法)。
然后,TestCommand方法将预期的交互与聚合中批准的交互进行比较。
public class DomainTestFixture<T>
where T : AggregateBase
{
private readonly T _agg;
private readonly StringBuilder _outputSb = new StringBuilder();
public DomainTestFixture(T agg, List<object> giveEvents)
{
_agg = agg;
_outputSb.AppendLine(string.Format("Given a {0}:", agg.GetType().Name));
giveEvents.ForEach(x => ((IAggregate) _agg).ApplyEvent(x));
_outputSb.AppendLine(
giveEvents.Count == 0
? string.Format("with no previously applied events.")
: string.Format("with previously applied events:")
);
giveEvents.ForEach(x => _outputSb.AppendLine(string.Format(" - {0}", x)));
((IAggregate) _agg).ClearUncommittedEvents();
var snapshot = ((IAggregate) _agg).GetSnapshot();
_outputSb.AppendLine(string.Format("which results in the state: {0}", snapshot));
}
public void TestCommand(Func<T, object> action)
{
var cmd = action.Invoke(_agg);
_outputSb.AppendLine(string.Format("When handling the command: {0}", cmd));
_outputSb.AppendLine(string.Format("Then the {0} reacts ", _agg.GetType().Name));
var raisedEvents = ((IAggregate) _agg).GetUncommittedEvents().Cast<object>().ToList();
_outputSb.AppendLine(
raisedEvents.Count == 0
? string.Format("with no raised events")
: string.Format("with the following raised events:")
);
raisedEvents.ForEach(x => _outputSb.AppendLine(string.Format(" - {0}", x)));
var snapshot = ((IAggregate) _agg).GetSnapshot();
var typ = snapshot.GetType();
_outputSb.AppendLine(string.Format("and results in the state: {0}", snapshot));
Approvals.Verify(_outputSb.ToString());
Assert.Pass(_outputSb.ToString());
}
}和一个例子用法
[Test]
public void Test_Some_Aggregate_Handle_Command()
{
var aggId = Guid.Empty;
var tester = new DomainTestFixture<PartAggregate>(
new PartAggregate(aggId, null),
new List<object>()
{
new PartOrdered(),
new PartReceived()
}
);
tester.TestCommand(
(agg) =>
{
var cmd = new RejectPart();
agg.Handle(cmd);
return cmd;
});
}https://stackoverflow.com/questions/13398588
复制相似问题