Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/199.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Unit testing 数据访问、单元测试、依赖注入_Unit Testing_Dependency Injection_Data Access - Fatal编程技术网

Unit testing 数据访问、单元测试、依赖注入

Unit testing 数据访问、单元测试、依赖注入,unit-testing,dependency-injection,data-access,Unit Testing,Dependency Injection,Data Access,我最近有一项任务,创建一个简单的实用程序,允许将数据从具有特殊格式的文件导入数据库。我用很少的类实现了控制台应用程序(程序类和业务逻辑类一起运行,业务逻辑类又和数据访问类一起运行)。一切正常,但现在我正在考虑创建一些单元测试和重构应用程序(我以前没有创建真正的单元测试,很久以前只是一堆集成测试,所以我相信这个应用程序是练习的完美领域) 所以,问题是:数据访问类是静态的,这不允许对其进行模拟,从而创建真正的单元测试。要解决这个问题,我需要创建一个接口并在数据访问类中实现它。此外,我还必须向业务逻辑

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

所以,问题是:数据访问类是静态的,这不允许对其进行模拟,从而创建真正的单元测试。要解决这个问题,我需要创建一个接口并在数据访问类中实现它。此外,我还必须向业务逻辑类添加一个构造函数,该类将接受该接口类型的参数。这意味着我将在application Main()方法中创建数据访问类,有人告诉我这不是最好的方法(入口点应该知道一些数据访问的事情,这真的可以吗?如果链更长或者应该有几个链呢?)。我知道我可以使用一些IoC容器,但我认为这是一个太简单的应用程序,无法使用容器


谢谢

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

  public void insert (...) {
      DataAccess.insert (...);
  }
现在您可以覆盖这些调用。我建议按如下方式拆分测试:

  • 创建两个测试,确保
    DataAccess
    在获得正确参数时做正确的事情

  • 在实体模型测试中,只需收集发送到
    insert()
    的参数。根本不要调用
    DataAccess

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


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

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

    互联网上有一些关于这个主题的文章,这里有一篇:

    我需要创建一个接口并在数据访问类中实现它。此外,我将不得不添加一个构造函数 到将 接受该接口的参数 类型。所以这意味着我最终会 在中创建数据访问类 应用程序Main()方法和 有些事告诉我这不是最好的 方法(如果 入口点应该知道一些 数据访问的东西?如果链 要长得多或者应该有 几条链条?)

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

    使您的业务逻辑层可测试的唯一方法是,完全按照您的设想将其与数据访问层隔离

    您的顶级应用程序就是责任所在——它是唯一需要知道具体数据访问类是什么的组件

    如果链长得多,或者有几个链,那没什么大不了的(尽管你可能想考虑如果它失控的话会崩溃一些应用层)。在<代码>模型视图演示者< /代码>应用程序<代码>视图>代码中考虑此潜在代码,其中<代码>演示者< /代码>依赖于<代码>客户服务>代码>,它依赖于<代码>存储库< /代码>和对<代码> ActudioService < /代码>的依赖性(这也依赖于<代码>存储库< /代码>):


    最后,如果您不想使用依赖项注入容器,则无需使用依赖项注入容器(尽管其中一些容器非常轻量级)-手动依赖项注入可以很好地工作,直到您开始到处重复(或者发现您希望在运行时配置依赖项).

    现在,我正在使用类型化数据集和自定义方法从文件读取和写入文件。最初我没有使用实体框架或linq2sql,因为在我编写这个应用程序的时候,我没有太多的时间用我没有经验的技术进行实验。但这是个好主意,也许我会修改我的DAL。补充评论作为答案,并没有太多space@Dev-回答问题会很快让人困惑。最终答案将被重新排序,亚伦可能会改变他的名字,甚至可能会删除他的答案。我建议在评论中回答-如果您需要比分配的字符更多的空间,您可以将响应分散到两条评论中。或者,如果您认为原始问题有助于其他人回答您的问题,您可以编辑原始问题以包含一些信息。谢谢Jeff,将把“答案”移到评论中。@Aaron,谢谢您的快速回复。如果我理解正确的话,建议是使用虚拟方法的包装器包装数据访问类,这样我就可以覆盖它们进行模拟。这是一个有趣的想法,但似乎我需要“复制”所有数据访问方法只是为了可测试性,每次我需要向数据访问类添加新方法时,我都必须创建一个合适的包装器。如果我在BL类中创建一个将创建数据访问对象的虚拟方法,这可以吗?如果我在BL类中创建一个将创建数据访问对象的虚拟方法,这可以吗?类似这样的内容:受保护的虚拟IDataAccess CreateDataAccess(){return new DataAccess();}然后我将能够重写单个方法来模拟数据访问对象。这种方法的缺点是什么?+1:很好
    public CustomerView() {
        IRespository       repository        = new ConcreteRepository();
        IAccountingService accountingService = new ConcreteAccountingService(repository);
        ICustomerService   customerService   = new ConcreteCustomerService(accountingService, repository)
        this._Presenter = new CustomerPresenter(customerService);
    }