Unit testing CommonDomain-如何对聚合根进行单元测试
我有一个使用Jonathan Oliver的CommonDomain和EventStore的小系统 如何对聚合根进行单元测试以验证引发的事件是否正确? 考虑以下聚合根:Unit testing CommonDomain-如何对聚合根进行单元测试,unit-testing,cqrs,event-sourcing,neventstore,commondomain,Unit Testing,Cqrs,Event Sourcing,Neventstore,Commondomain,我有一个使用Jonathan Oliver的CommonDomain和EventStore的小系统 如何对聚合根进行单元测试以验证引发的事件是否正确? 考虑以下聚合根: public class Subscriber : AggregateBase { private Subscriber(Guid id) { this.Id = id; } private Subscriber(Guid id, stri
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
//排列
var id=Guid.NewGuid();
var电子邮件=”test@thelightfull.com";
var registeredDate=DateTimeOffset.Now;
//表演
var subscriber=subscriber.Create(id、电子邮件、registeredDate);
//断言
var eventsRaised=subscriber.GetEvents() 我发现,AggregateBase
显式地实现了iaggergegate
接口,该接口公开了ICollection getuncommitteedvents()代码>方法
因此,单元测试如下所示:
var eventsRaised=((IAggregate)订户).GetUncommittedEvents()代码>
并且不需要依赖于EventStore。这里有一个相当简单的测试夹具,它使用NUnit和ApprovalTests来测试公共域聚合根。(不需要认可测试——只是让生活变得简单而已)
假设是
1) 该装置通过一个聚合(可能已经设置为特定状态)以及一系列要应用的“给定”事件进行实例化。
2) 然后,测试将调用一个特定的命令处理程序作为TestCommand方法的一部分-当前预期是一个Func,它返回所处理的命令
3) 聚合快照、命令和事件都包含“rich”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());
}
}
公共类域测试夹具
其中T:AggregateBase
{
私有只读T_agg;
私有只读StringBuilder _outputSb=新StringBuilder();
公共领域测试装置(T agg,列出事件)
{
_agg=agg;
_outputSb.AppendLine(string.Format(“给定一个{0}:”,agg.GetType().Name));
giveEvents.ForEach(x=>((iaggergate)_agg.ApplyEvent(x));
_输出线(
giveEvents.Count==0
?string.Format(“没有以前应用的事件”)
:string.Format(“使用以前应用的事件:”)
);
giveEvents.ForEach(x=>_outputSb.AppendLine(string.Format(“-{0}”,x));
((IAggregate)_agg.ClearUncommittedEvents();
var snapshot=((IAggregate)_agg.GetSnapshot();
_outputSb.AppendLine(string.Format(“导致状态:{0}”,快照));
}
公共void TestCommand(Func操作)
{
var cmd=action.Invoke(_agg);
_outputSb.AppendLine(string.Format(“处理命令时:{0}”,cmd));
_outputSb.AppendLine(string.Format(“然后{0}反应”,_agg.GetType().Name));
var raisedEvents=((iaggergate)_agg.GetUncommittedEvents().Cast().ToList();
_输出线(
RaiseEvents.Count==0
?string.Format(“无引发事件”)
:string.Format(“具有以下引发的事件:”)
);
raiseEvents.ForEach(x=>_outputSb.AppendLine(string.Format(“-{0}”,x));
var snapshot=((IAggregate)_agg.GetSnapshot();
var typ=snapshot.GetType();
_outputSb.AppendLine(string.Format(“并导致状态:{0}”,快照));
批准。验证(_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;
});
}
[测试]
public void Test\u Some\u Aggregate\u Handle\u Command()命令
{
var aggId=Guid.Empty;
var测试仪=新域测试装置(
新PartAggregate(aggId,null),
新名单()
{
新PartOrdered(),
新收到的部分()
}
);
tester.test命令(
(agg)=>
{
var cmd=新的RejectPart();
聚合句柄(cmd);
返回cmd;
});
}
我刚刚用在不同地方收集的代码(,)推了推
这是NEventStore
的一个非常基本的实现,它使用CommonDomain
来重建聚合状态,并使用EventSpecification
基本测试类来测试聚合行为。可能值得进行更高级别的测试(命令处理程序)。请看我的博客,以后再发一篇关于这个主题的文章(虽然不是针对CommonDomain的)。谢谢,这正是我需要的。