我目前正在为我的域模型编写单元测试。
为了提供一些上下文,我有一个Role Group类,它有一个角色列表,它还有一个当前分配了该角色组的用户列表。
角色组被分配给用户,因此执行此操作的所有方法都在用户域模型中。这意味着角色组端的Users属性基本上是从数据库中提取的。
角色组和用户都是聚合根,它们都可以单独存在。
单元测试包含从数据库填充的列表的域模型
我正在努力的是,我无法测试下面的CanArchive方法,因为我无法将用户添加到属性中。除了使用Add方法之外,我不想使用它,因为它打破了域模型控制自己数据的整个想法。
所以我不确定我的域模型是否是错误的,或者这个逻辑是否应该放在服务中,因为它是两个聚合根之间的交互。
角色组类:
public bool Archived { get; private set; }
public int Id { get; private set; }
public string Name { get; private set; }
public virtual IList<Role> Roles { get; private set; }
public virtual IList<User> Users { get; private set; }
更新存档方法:
private void UpdateArchived(bool archived)
{
if (archived && !CanArchive())
{
throw new InvalidOperationException("Role Group can not be archvied.");
}
Archived = archived;
}
检查角色组是否可以存档的方法
private bool CanArchive()
{
if (Users.Count > 0)
{
return false;
}
return true;
}
方法,该方法在User类中设置用户的角色组当在用户界面中创建或更新用户时,会调用此操作。
private void UpdateRoleGroup(RoleGroup roleGroup)
{
if (roleGroup == null)
{
throw new ArgumentNullException("roleGroup", "Role Group can not be null.");
}
RoleGroup = roleGroup;
}
几个想法:
-
对域对象进行单元测试不应该依赖于持久层的东西。一旦你做到了这一点,你就有了一个集成测试。
-
在DDD中,通过数据库集成两个聚合之间的更改理论上不是一个好主意。由
User.UpdateRoleGroup()
引起的更改应该保留在User
聚合中,或者触发其他聚合上的公共域方法对其进行突变(以最终一致的方式)。如果这些方法是公开的,那么它们也应该可以从测试中访问。 -
对于EntityFramework,这些都不重要,因为它不擅长建模只读集合,而且很可能会有一个可变的Users列表。我不认为在测试中调用
roleGroup.Users.Add(...)
来设置数据是一个大问题,尽管您不应该在生产代码中这样做。也许,正如@NikolaiDante所建议的那样,将internal
和internalsVisibleTo
列为您的测试项目,并将其封装到公共只读集合中,会降低风险。
我正在努力的是,我无法测试下面的CanArchive方法,因为我无法将用户添加到属性中。
从数据库加载RoleGroup
实例的框架如何填充用户?这是你必须问自己的问题,为你的单元测试找到解决方案。只要用同样的方法。
我不知道你用什么语言。例如,在Java中,您可以使用反射api来设置私有字段。还有很多测试框架为这项工作提供了方便的方法,例如Deencaapsulation或Whitebox。