4

我最近有一项任务是创建一个简单的实用程序,该实用程序允许将具有特殊格式的文件中的数据导入数据库。我用很少的类实现了控制台应用程序(程序类与业务逻辑类一起操作,业务逻辑类又与数据访问类一起操作)。一切正常,但现在我正在考虑创建一些单元测试和重构应用程序(我之前没有创建过真正的单元测试,很久以前只是一堆集成测试,所以我相信这个应用程序是练习的完美领域) .

所以,问题来了:数据访问类已经变成静态的,这不允许模拟它并因此创建真正的单元测试。为了解决这个问题,我需要创建一个接口并在数据访问类中实现它。此外,我必须向业务逻辑类添加一个构造函数,该类将接受该接口类型的参数。所以这意味着我最终将在应用程序 Main() 方法中创建数据访问类,并且有些东西告诉我这不是最好的方法(入口点应该知道一些数据访问的事情真的可以吗?如果链是更长的时间还是应该有几个链条?)。我知道我可以使用一些 IoC 容器,但我认为这对于使用容器来说太简单了。

谢谢!

4

3 回答 3

6

我需要创建一个接口并在数据访问类中实现它。此外,我必须向业务逻辑类添加一个构造函数,该类将接受该接口类型的参数。所以这意味着我最终将在应用程序 Main() 方法中创建数据访问类,并且有些东西告诉我这不是最好的方法(入口点应该知道一些数据访问的事情真的可以吗?如果链是更长还是应该有几个链条?)

相反!这最好的方法,至少从可测试性的角度来看。

使您的业务逻辑层可测试的唯一方法是通过完全按照您的计划将其与您的数据访问层隔离开来。

您的顶级应用程序是停止工作的地方——它是唯一需要知道具体数据访问类是什么的组件。

如果链更长或有多个链,那没什么大不了的(尽管如果失控,您可能需要考虑折叠一些应用程序层)。Model-View-Presenter考虑应用程序中的这个潜在代码View,其中Presenter依赖于 a CustomerService,依赖于 aRepository和依赖于 an AccountingService(这也依赖于Repository):

public CustomerView() {
    IRespository       repository        = new ConcreteRepository();
    IAccountingService accountingService = new ConcreteAccountingService(repository);
    ICustomerService   customerService   = new ConcreteCustomerService(accountingService, repository)
    this._Presenter = new CustomerPresenter(customerService);
}

最后,如果您不想使用依赖注入容器(尽管其中一些非常轻量级),则无需使用依赖注入容器 - 手动依赖注入工作正常,直到您开始在整个地方重复自己(或发现您想要配置运行时的依赖项)。

于 2009-09-21T17:11:13.080 回答
1

假设您使用的是 LINQ to SQL,也许您可​​以使用存储库模式将 DataContext 包装到您以后可以模拟的接口中,从而使单元测试成为可能。

网上有一些关于这个主题的文章,这里有一篇: http ://andrewtokeley.net/archive/2008/07/06/mocking-linq-to-sql-datacontext.aspx

于 2009-09-21T15:16:26.370 回答
0

这是一个简单的解决方案:不要直接调用数据访问类,而是使用辅助方法:

  public void insert (...) {
      DataAccess.insert (...);
  }

现在您可以覆盖这些调用。我建议像这样拆分测试:

  1. 创建几个测试以确保DataAccess在获得正确参数时执行正确的操作。

  2. 在模型测试中,只需收集发送到insert(). 根本不要打电话DataAccess

#1 中的测试将确保将数据写入数据库将正常工作,而#2 中的测试将确保您DataAccess使用正确的值调用。后面的测试将运行得非常快,这将使测试特殊情况等变得容易。

您也不需要一直从 #1 运行测试。仅当您在发布中DataAccess或发布之前更改某些内容时。这将使测试变得高效和愉快。

于 2009-09-21T14:53:22.257 回答