对包含从数据库填充的列表的域模型进行单元测试
Unit Testing a Domain Model Containing Lists Populated From The Database
我目前正在为我的领域模型编写单元测试。
为了说明一些上下文,我有一个角色组 class,它有一个角色列表,它还有一个当前分配给他们的角色组的用户列表。
一个角色组被分配给一个用户,所以所有的方法都在用户域模型中。这意味着角色组端的用户 属性 基本上是从数据库中提取的。
角色组和用户都是聚合根,它们都可以独立存在。
对包含从数据库填充的列表的域模型进行单元测试
我苦苦挣扎的是我无法测试下面的 CanArchive 方法,因为我无法将用户添加到 属性。除了不好的地方是使用我不想使用的 Add 方法,因为它打破了域模型控制自己的数据的整个想法。
所以我不确定我的领域模型是否错误,或者这个逻辑是否应该放在服务中,因为它是两个聚合根之间的交互。
角色组Class:
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;
}
在用户中设置用户角色组的方法class
在用户界面中创建或更新用户时调用此方法。
private void UpdateRoleGroup(RoleGroup roleGroup)
{
if (roleGroup == null)
{
throw new ArgumentNullException("roleGroup", "Role Group can not be null.");
}
RoleGroup = roleGroup;
}
What I am struggling with is I can not test the CanArchive method below because I have no way off adding in a User to the property.
从数据库加载 RoleGroup
实例的框架如何填充用户?这是您必须问自己的问题,以便为您的单元测试找到解决方案。照着做就行了。
我不知道你用的是什么语言。例如,在 Java 中,您可以使用反射 api 来设置私有字段。还有很多测试框架为这项工作提供了方便的方法,例如Deencapsulation or Whitebox.
一些想法:
域对象的单元测试不应该依赖于持久层的东西。一旦这样做,您就会进行集成测试。
通过数据库整合两个聚合之间的变化在DDD中理论上不是一个好主意。由 User.UpdateRoleGroup()
引起的更改应该保留在 User
聚合中,或者触发其他聚合上的 public 域方法来改变它们(以最终一致的方式)。如果这些方法是 public,它们也应该可以从测试中访问。
使用 Entity Framework、none 确实很重要,因为它不擅长建模 read-only 集合,您很可能会有一个可变的用户列表.我不认为调用 roleGroup.Users.Add(...)
在测试中设置数据是一个大问题,即使您不应该在生产代码中这样做。也许将 internal
与 internalsVisibleTo
你的测试项目一起制作列表 - 正如@NikolaiDante 建议的那样 - 并将其包装到 public 只读集合中会使它的危险性降低一些。
我目前正在为我的领域模型编写单元测试。
为了说明一些上下文,我有一个角色组 class,它有一个角色列表,它还有一个当前分配给他们的角色组的用户列表。
一个角色组被分配给一个用户,所以所有的方法都在用户域模型中。这意味着角色组端的用户 属性 基本上是从数据库中提取的。
角色组和用户都是聚合根,它们都可以独立存在。
对包含从数据库填充的列表的域模型进行单元测试
我苦苦挣扎的是我无法测试下面的 CanArchive 方法,因为我无法将用户添加到 属性。除了不好的地方是使用我不想使用的 Add 方法,因为它打破了域模型控制自己的数据的整个想法。
所以我不确定我的领域模型是否错误,或者这个逻辑是否应该放在服务中,因为它是两个聚合根之间的交互。
角色组Class:
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;
}
在用户中设置用户角色组的方法class 在用户界面中创建或更新用户时调用此方法。
private void UpdateRoleGroup(RoleGroup roleGroup)
{
if (roleGroup == null)
{
throw new ArgumentNullException("roleGroup", "Role Group can not be null.");
}
RoleGroup = roleGroup;
}
What I am struggling with is I can not test the CanArchive method below because I have no way off adding in a User to the property.
从数据库加载 RoleGroup
实例的框架如何填充用户?这是您必须问自己的问题,以便为您的单元测试找到解决方案。照着做就行了。
我不知道你用的是什么语言。例如,在 Java 中,您可以使用反射 api 来设置私有字段。还有很多测试框架为这项工作提供了方便的方法,例如Deencapsulation or Whitebox.
一些想法:
域对象的单元测试不应该依赖于持久层的东西。一旦这样做,您就会进行集成测试。
通过数据库整合两个聚合之间的变化在DDD中理论上不是一个好主意。由
User.UpdateRoleGroup()
引起的更改应该保留在User
聚合中,或者触发其他聚合上的 public 域方法来改变它们(以最终一致的方式)。如果这些方法是 public,它们也应该可以从测试中访问。使用 Entity Framework、none 确实很重要,因为它不擅长建模 read-only 集合,您很可能会有一个可变的用户列表.我不认为调用
roleGroup.Users.Add(...)
在测试中设置数据是一个大问题,即使您不应该在生产代码中这样做。也许将internal
与internalsVisibleTo
你的测试项目一起制作列表 - 正如@NikolaiDante 建议的那样 - 并将其包装到 public 只读集合中会使它的危险性降低一些。