Delphi风格:如何构建可单元测试代码的数据模块? [英] Delphi style: How to structure data modules for unit-testable code?

查看:180
本文介绍了Delphi风格:如何构建可单元测试代码的数据模块?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一些关于构建Delphi程序以提供可维护性的建议。几十年来,我已经来到Delphi编程,大部分是C / C ++,尽管我第一次学习使用Turbo Pascal进行编程,所以我对基本语言并不感到不舒服。在我以前的C ++和C#的经验中,我通过使用cxxtest和NUnit成为了TDD转换。



我继承了我现在负责维护的这个程序。它主要由表单和几个数据模块组成。应用程序业务逻辑和数据访问主要分散在表单上,​​而数据模块主要是全局ADO对象生存的地方。数据库访问通常通过引用TADOQuery或TADOCommand的全局实例来完成,将SQL文本格式化为对象的相关属性,并调用其Open或Execute方法。



我试图将业务逻辑放到一定程度的封装,可以进行单元测试。我看过这个答案,从形式的抽象逻辑来说,这是完全有道理的。我想知道数据访问的最佳做法是什么。我的想法是,数据模块应该公开一种特定于应用程序的mini-API(可能是所有的虚拟方法),以便它们可以被模拟对象替换成测试。 另一个答案中的链接显示了一些让我相信的例子我在正确的轨道上,但我仍然希望看到有关数据模块的一些最佳实践文档。我可以通过Google找到的大部分页面都提供了与设计时可以做的所有酷的东西一样的例子,它们将数据绑定控件绑定到查询和这种事情上,我对此并不感兴趣

解决方案

个人而言,我不是TDataModule的粉丝。鼓励良好的OO设计原则很少。如果所有这些都是DB组件的一个方便的容器,这将是一件事情,但是经常会成为在域层中更好的业务逻辑的倾倒场所。当这种情况发生时,它会变成一个神级和一个依赖磁铁。



添加到这个bug(或者也许它的一个功能) a href =http://groups.google.com/group/comp.lang.pascal.delphi.databases/browse_thread/thread/a938e0b3d6e1a9f7/1161ad39ff46907b?hl=zh-CN&ie=UTF-8&q=data+module+ data + source#1161ad39ff46907brel =noreferrer> Delphi 2 ,导致窗体的数据感知控件丢失数据源,如果这些数据源位于窗体之前未打开的单元中。 p>

我的建议




  • 在您的UI和您的数据库

  • 尽可能多地将业务逻辑推入域对象。

  • 使您的UI和数据持久层成为浅可能通过使用设计建筑



如果您不熟悉该技术,请参考作为域驱动的设计。它当然不是唯一的解决方案,但它是一个很好的解决方案。基本前提是,UI,业务逻辑和数据库以不同的速率和不同的原因进行更改。因此,将业务逻辑作为问题域的模型,并将其与UI和数据库保持分离。



如何使我的代码更具可测试性? strong>



通过将业务逻辑移动到自己的层,您可以测试它,而不受UI或数据库的干扰。这并不意味着您的代码只会因为将其置于自己的层面而固有地可测试。使遗留代码可测试是一项艰巨的任务。大多数遗留代码是紧密耦合的,所以你将花费大量的时间把它分成具有明确责任的课程。



这是德尔福风格?



这取决于你的观点。传统上,大多数Delphi应用程序是通过一起开发UI和数据库而创建的。在表单设计器上删除几个数据库感知控件。使用字段添加/更新表以存储控件的数据。使用事件处理程序使用自由的业务逻辑。中提琴!你刚刚烤了一个应用程序。对于非常小的应用程序,这是一个很好的节省时间。但是让我们不要自拔,小的应用程序往往变成大型应用程序,这种设计成为一种不可持续的维护噩梦。



这真的不是语言的错误。您可以从数百个VB,C#和Java商店找到相同的快速/脏/短视设计。这些类型的应用程序是新手开发人员不了解任何更好的(有经验的开发人员应该更好地了解)的结果,这是一个IDE,使其变得如此容易,并且能够快速完成工作的压力。



Delphi社区(正如其他社区一样)在很长时间一直主张更好的设计技术。


I am looking for some advice about structuring Delphi programs for maintainability. I've come to Delphi programming after a couple of decades of mostly C/C++ though I first learned to program with Turbo Pascal, so I'm not uncomfortable with the basic language. In my previous experience with C++ and C#, I became a TDD convert through using cxxtest and NUnit.

I have inherited this program that I am now responsible for maintaining. It consists mainly of forms, and a couple of data modules. The application business logic and data access is mainly scattered about the forms, and the data modules are mostly just places for global ADO objects to live. The database access is generally done by referring to a global instance of TADOQuery or TADOCommand, formatting SQL text right into the relevant property of the object, and calling its Open or Execute method.

I am trying to get the business logic into a degree of encapsulation where it can be unit-tested. I've seen this answer and it makes perfect sense as far as abstracting logic from forms. I am wondering what the best practices are for data access. My thinking is that the data modules should expose a sort of app-specific mini-API (probably with all virtual methods) so that they can be replaced with mock objects for testing. The link at this other answer shows some examples that lead me to believe I'm on the right track, but I'm still interested in seeing some kind of best practices document about data modules. Most of the pages that I can find through Google present the same kind of examples about all the cool stuff you can do at design time with hooking up data-bound controls to queries and that sort of thing, which I'm not very interested in at the moment.

解决方案

Personally I'm not a fan of TDataModule. It does very little to encourage good OO design principles. If all it was used for was a convenient container for DB components that would be one thing but far too often it becomes a dumping ground for business logic that would be better off in a domain layer. When this happens it winds up becoming a god class and a dependency magnet.

Add to this a bug (or maybe its a feature) that's continued to exist since at least Delphi 2 that causes a form's data aware controls to lose their data sources if those data sources are located in a unit that isn't opened before the form.

My suggestion

  • Add a domain layer between your UI and your database
  • Push as much of your business logic into domain objects as possible.
  • Make your UI and your data persistence layers as shallow as possible by using design and architectural patterns to delegate decision making to the domain layer.

If you're not familiar with it the technique is referred to as domain driven design. Its certainly not the only solution but its a good one. The basic premise is that the UI, business logic and database change at different rates and for different reasons. So make the business logic a model of the problem domain and keep it separated from the UI and database.

How does this make my code more testable?

By moving the business logic to its own layer you can test it without interference from from either the UI or the database. This doesn't mean your code will be inherently testable simply because you put it in its own layer. Making legacy code testable is a difficult task. Most legacy code is tightly coupled so you will spend a good deal of time pulling it apart into classes with clearly defined responsibilities.

Is this the Delphi style?

That depends on your perspective. Traditionally, most Delphi applications were created by developing the UI and the database in tandem. Drop a few db aware controls on the form designer. Add/update a table with fields to store the control's data. Sprinkle with a liberal amount of business logic using event handlers. Viola! You just baked an application. For very small applications this is a great time saver. But lets not kid ourselves, small applications tend to turn into big ones and this design becomes an unsustainable maintenance nightmare.

This really isn't the fault of the language. You find the same quick/dirty/shortsighted designs from hundreds of VB, C# and Java shops. These kinds of applications are the result of novice developers that don't know any better (and experienced developers that should know better), an IDE that makes it so easy to do and pressure to get the job done quickly.

There are those in the Delphi community (as there are in other communities) that have been advocating better design techniques for a long time.

这篇关于Delphi风格:如何构建可单元测试代码的数据模块?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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