是的,这是一个良好的开端,但是,其接口比有依赖注入少一个优先的。如果你所有的遗留类都获得了接口,但是在内部隐藏,它们仍然是相互依赖的,这些类仍然不容易测试。举例来说,假设你有一个看起来像这样两类:
Public Class LegacyDataAccess
Public Function GetAllSales() As List(Of SaleDto)
' Do work with takes a long time to run against real DB
End Function
End Class
Public Class LegacyBusiness
Public Function GetTotalSales() As Integer
Dim dataAccess As New LegacyDataAccess()
Dim sales As List(Of SaleDto) = dataAccess.GetAllSales()
' Calculate total sales
End Function
End Class
我知道你已经说... “我希望遗留代码至少是分层的那么好”,但让用它作为一些遗传代码的例子,这些遗传代码很难测试。难以测试的原因是因为代码伸出数据库并对数据库执行耗时的查询,然后从中计算结果。因此,为了以当前状态测试它,您需要先将大量测试数据写入数据库,然后运行代码以查看它是否基于插入的数据返回正确的结果。不得不写一个这样的测试是有问题的,因为:
- 这是一个痛苦的代码写入到安装测试
- 测试将是脆弱,因为它取决于正常工作外数据库和它含所有正确的支持数据
- 测试将需要很长时间才能运行
正如你正确地观察,接口单元测试非常重要。因此,当你建议,让我们来添加界面,看看它使任何更容易测试:
Public Interface ILegacyDataAccess
Function GetAllSales() As List(Of SaleDto)
End Interface
Public Interface ILegacyBusiness
Function GetTotalSales() As Integer
End Interface
Public Class LegacyDataAccess
Implements ILegacyDataAccess
Public Function GetAllSales() As List(Of SaleDto) _
Implements ILegacyDataAccess.GetAllSales
' Do work with takes a long time to run against real DB
End Function
End Class
Public Class LegacyBusiness
Implements ILegacyBusiness
Public Function GetTotalSales() As Integer _
Implements ILegacyBusiness.GetTotalSales
Dim dataAccess As New LegacyDataAccess()
Dim sales As List(Of SaleDto) = dataAccess.GetAllSales()
' Calculate total sales
End Function
End Class
所以现在我们有接口,但实际上,如何使它变得更容易测试?现在我们可以轻松创建一个模拟数据访问对象,它实现相同的接口,但这不是真正的核心问题。问题是,我们如何让业务对象使用模拟数据访问对象而不是真实的?要做到这一点,你需要通过引入依赖注入来将你的重构提升到下一个层次。真正的罪魁祸首是New
关键字在以下行业务类:
Dim dataAccess As New LegacyDataAccess()
商务舱清楚地依赖于数据访问类,但目前它是隐藏这一事实。这是说谎的依赖关系。这就是说,来吧,很简单,只需调用这个方法,我就会返回结果 - 这就是所需要的。当真的时,它需要更多的东西。现在,让我们说,我们从卧谈它的依赖停止了它,并使它所以它毫不掩饰地说他们,是这样的:
Public Class LegacyBusiness
Implements ILegacyBusiness
Public Sub New(dataAccess As ILegacyDataAccess)
_dataAccess = dataAccess
End Sub
Private _dataAccess As ILegacyDataAccess
Public Function GetTotalSales() As Integer _
Implements ILegacyBusiness.GetTotalSales
Dim sales As List(Of SaleDto) = _dataAccess.GetAllSales()
' Calculate total sales
End Function
End Class
现在,你可以看到,这个类是多容易测试。我们不仅可以轻松创建模拟数据访问对象,现在我们可以轻松地将模拟数据访问对象注入到业务对象中。现在我们可以创建一个模拟,它可以快速而轻松地返回我们希望返回的数据,然后查看业务类是否返回正确的计算 - 不涉及数据库。
不幸的是,虽然向现有类添加接口非常简单,但重构它们以使用依赖注入通常需要更多的工作。您可能需要计划出哪些类最适合首先处理。您可能需要创建一些中介的旧式封装,这些封装符合代码的习惯,因此您在重构代码的过程中不会破坏现有代码。这并不是一件快速简单的事情,但如果你耐心并且长期坚持下去,就有可能做到这一点,你会很高兴你做到了。
感谢DI提醒。 +1。 – w0051977
并提供全面的解答。 – w0051977
谢谢。我将不胜感激,如果你会看看我的数据仓库/ VB.NET问题在这里:http://stackoverflow.com/questions/18495622/data-warehouse-type-solution#18495622。你提供了设计模式类型问题的好答案,所以我想我会问。 – w0051977