数据访问,单元测试,依赖注入 [英] Data access, unit testing, dependency injection

查看:181
本文介绍了数据访问,单元测试,依赖注入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近有一个任务来创建一个简单的实用程序,允许从具有特殊格式的文件将数据导入数据库。我已经实现了几个类的控制台应用程序(程序类操作与业务逻辑类,业务逻辑类依次使用数据访问类)。一切都可以正常工作,但是现在我正在考虑创建一些单元测试和重构应用程序(以前没有创建真正的单元测试,只是很久以前的一堆集成测试,所以我相信这个应用程序是完美的实践领域) 。



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



谢谢!

解决方案


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


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



使您的业务逻辑层可测试的唯一方法是将其与您的数据访问层通过做你正在考虑的事情。



您的顶级应用程序是降级的地方 - 它是唯一需要知道具体数据访问类的组件。



如果链条长得多或有几条链,那没有什么大不了的(尽管如果这些链接失败,您可能希望考虑折叠一些应用程序层)。在 Model-View-Presenter 应用程序的视图中考虑这个潜在的代码,其中 Presenter 依赖于一个 CustomerService ,它依赖于 Repository 和依赖关系一个 AccountingService (这也取决于资源库):



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

最后,如果没有依赖注入容器,则不需要使用想要(虽然其中有些是令人惊讶的轻量级) - 手动依赖注入工作正常,直到您在整个地方重新开始重复(或者想要在运行时配置依赖项)。


I've recently got a task to create a simple utility that allows to import data from a file with special format to the database. I've implemented console application with few classes(Program class operates with business logic class, business logic class in turn operates with data access class). Everything works ok, but now I'm thinking about creating some unit tests and refactoring application (I have not created real unit tests before, just a bunch of integration tests a long time ago, so I believe this application is perfect field for practicing).

So, here is the problem: the data access class has been made static, this doesn't allow to mock it and as a result create real unit tests. To fix this I need to create an interface and implement it in the data access class. Also I will have to add a constructor to the business logic class that will accept parameter of that interface type. So this means that I will end up creating data access class in the application Main() method and something tells me this not the best approach (is it really ok that the entry point should know about some data access things? what if the chain is much longer or there should be several chains?). I know I can use some IoC container, but I think this is too simple application to use containers.

Thanks!

解决方案

I need to create an interface and implement it in the data access class. Also I will have to add a constructor to the business logic class that will accept parameter of that interface type. So this means that I will end up creating data access class in the application Main() method and something tells me this not the best approach (is it really ok that the entry point should know about some data access things? what if the chain is much longer or there should be several chains?)

On the contrary! This is the best approach, at least from a testability perspective.

The only way to make your business logic layer testable is to isolate it from your data access layer by doing exactly what you're contemplating.

Your top-level application is where the buck stops - it's the only component that should need to know what the concrete data access class is.

If the chain is much longer or there are several chains, that's no big deal (though you may want to consider collapsing some application layers if it gets out of hand). Consider this potential code in a Model-View-Presenter app's View, where the Presenter has a dependency on a CustomerService, which has a dependency on a Repository and a dependency on an AccountingService (which is also dependent on the Repository):

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

Finally, there's no need to use a dependency injection container if you don't want to (though some of them are surprisingly lightweight) - dependency injection by hand works fine until you start repeating yourself all over the place (or find you want to configure the dependencies at runtime).

这篇关于数据访问,单元测试,依赖注入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆