我可以测试使用单例的类 - 或者是否有其他解决方案

时间:2017-08-29 09:30:00

标签: c# unit-testing nunit

我遇到了一个问题。我创建了一个使用IoC的解决方案。但是,我有一个致命的缺陷 - 我使用的主要DTO(数据传输对象 - 所以,通过图层的类)包含,例如,具有名称,姓氏,DateOfBirth,StatusId ...和列表的人有效状态。

创建Person类时会填充状态,并且数据来自参考数据存储库...此存储库是一个单例并从缓存中获取数据(最初是从数据库获取数据)。

所以,

Name string {get; set;}
Surname string {get; set;}
StatusId int {get; set;}
Statuses List<ReferenceItem> {get; set;} = ReferenceData.GetData(DataType.ClientStatus);

在我的单元测试中,我最终依赖于ReferenceData类,它是一个单例。有没有办法以某种方式注入模拟ReferenceData类?或者我的设计存在缺陷,我需要重新设计我的Person类吗?

2 个答案:

答案 0 :(得分:2)

你必须重新设计你的类并使用构造函数注入。 按照这个例子(指你的):

class Person {
  public string Name { get; set; }
  public string Surname { get; set; }
  public int StatusId { get; set; }
  public List<ReferenceItem> Statuses { get; set; }

  public Person(IReferenceDataProvider provider) {
     Statuses = provider.GetData(DataType.ClientStatus);
  }
}

或者您可以直接使用IoC容器来解析构造函数中的依赖项:

... 
public Person() {
   var provider = IoC.Resolve<IReferenceDataProvider>();
   Statuses = provider.GetData(DataType.ClientStatus);
}
...

无论如何,你必须抽象你的类引用并使用接口。 希望这可以提供帮助。

答案 1 :(得分:1)

正如其他人指出能够测试你的代码一样,你应该重新设计代码是可测试的 我认为,您正在使用DTO(数据传输对象)通过不同的层传递数据,这种责任应该是这些对象应该对其中一个层具有最小的依赖性。
在您的情况下,您的DTO依赖于静态方法或注入接口,甚至更糟糕的是IoC容器。删除所有这些并使您的DTO成为负责数据的对象。

public class Person
{
    public string Name{ get; set; }
    public string Surname { get; set; }
    public int StatusId { get; set; }
    public List<ReferenceItem> Statuses { get; set; }
}

然后,在您创建Person实例的任何地方,您都必须注入IReferenceDataProvider 或者,您可以引入Factory抽象来创建Person

的实例
public interface IPersonFactory
{
    Person Create(string name, string surname, int statusId);
}

实施

public class PersonFactory
{
    private readonly IReferenceDataProvider _dataProvider;

   public PersonFactory(IReferenceDataProvider dataProvider)
   {
       _dataProvider = dataProvider;
   }

   public Person Create(string name, string surname, int statusId)
   {
       return new Person
       {
           Name = name,
           Surname = surname,
           StatusId = statusId,
           Statuses = _dataProvider.GetData(DataType.ClientStatus)
       };
   }
}
相关问题