7

我有一个非常以数据为中心的应用程序,用 Python / PyQt 编写。我计划进行一些重构以真正将 UI 与核心分开,主要是因为还没有任何真正的测试到位,而且显然必须改变。

已经有一些分离,我认为我已经以正确的方式做了很多事情,但它远非完美。两个例子,告诉你什么样的事情困扰着我:

  • 当用户右键单击一个数据对象的表示时,弹出的上下文菜单是由该数据对象创建的,尽管这个数据对象(本质上是一个数据库行的 ORM 表示)显然应该与 UI 无关.

  • 当一些东西被写入数据库,但写入失败(例如,因为数据库记录被不同的用户锁定),经典的“重试/中止”消息框会呈现给用户。这个对话框是由数据提供者*创建的,尽管提供者显然不应该有任何 UI 功能。显然,提供者可以改为引发异常或以其他方式指示失败,并且 UI 可以捕获并采取相应的行动。

    * 这是我用来表示基本上代表数据库表并在其数据对象和数据库引擎之间进行调解的对象的词;我不确定这是否是通常所说的“提供者”

我没有测试经验,所以我不容易“感觉到”可测试性问题或类似问题,但在我开始之前,必须进行一些重组。

不涉及复杂的业务逻辑(它主要只是 CRU D,是的,即使没有 D ),这将比重写更重组,所以我并不真正关心引入回归错误,就像在这个问题中讨论的那样。

我的计划是在开始重构时考虑到 UI 部分可以很容易地被替换为 Web 前端或基于文本的界面而不是 Qt 界面的想法。另一方面,核心仍然会使用 Qt 本身,因为在很多地方都使用了信号/槽机制,例如数据对象发出changed信号来指示,嗯,你知道什么。

所以,我的问题是:这是提高可测试性和可维护性的可行方法吗?任何其他评论,特别是考虑到 Python ?

4

4 回答 4

7

如果您还没有这样做,请阅读 Michael Feathers 的“有效地使用遗留代码”——它正是处理这种情况,并提供了丰富的技术来处理它。

他提出的一个关键点是在重构之前尝试进行一些测试。由于它不适合单元测试,因此请尝试进行一些端到端测试。我相信 Qt 有自己的驱动 GUI 的测试框架,所以添加测试来针对已知数据库操作 GUI 并验证结果。当您清理代码时,您可以使用单元测试替换或扩充端到端测试。

于 2010-01-17T16:58:56.207 回答
2

如果您想从所有其他部分中提取应用程序的所有 GUI 部分以测试您的所有应用程序,您应该使用 Model-View-Presenter:您可以在此处此处找到一些解释。

使用此模型,您的应用程序的所有服务都使用演示者,而只有用户可以直接与视图(GUI 部分)交互。演示者正在管理来自应用程序的视图。在您想要修改 GUI 框架的情况下,您将拥有一个独立于您的应用程序的 GUI 部分。您唯一需要修改的是演示者和视图本身。

对于您想要的 GUI 测试,您只需为演示者编写单元测试。如果你想测试 GUI 使用,你需要创建集成测试

希望有帮助!

于 2010-01-17T19:43:25.113 回答
1

我之前已经针对 UI/后端分离的大型遗留代码进行了重构。这很有趣,也很有意义。

/称赞 ;)

无论人们称之为什么模式,或者它是 MVC 的一部分,拥有一个非常清晰的API 层都是非常宝贵的。如果可能,您可以通过调度程序路由所有 UI 请求,该调度程序可以让您更好地控制 UI<->Logic 通信,例如。实现缓存,身份验证等。

可视化:

[QT Frontend]
[CLIs]             <=======> [Dispatcher] <=> [API] <==> [Core/Model]
[SOAP/XMPRPC/Json]
[API Test Suite]

这边走

  • 添加测试套件来测试您的 API 更容易。
  • 此外,它还使添加更多 UI 的方式更加统一和容易。
  • API 文档:假设您想通过一些 RPC 接口记录和公开 API,生成 API 文档会更容易。如果有人不同意 API 文档的重要性,可以随时查看 Twitter API,它是成功的。
  • 您可以快速将 API 层导入 python shell 并使用它

API 设计可以在您开始为 API 层编码之前进行。根据应用程序,您可能希望获得 zinterfaces 等软件包的帮助。这是我在编写非常小的应用程序时所采用的一般方法,它对我来说从未失败过。

看看

这种方法的一个明显优势是在您拥有 API 层和新 UI 之后,您现在可以返回到遗留代码并以更小的步骤修复/重构它。

其他建议是准备好您的测试套件。请参阅 interstar 的建议:在棕地应用程序中实施单元测试的首要任务是什么?.

于 2010-01-27T11:02:16.240 回答
1

有一点,到目前为止没有提到,也没有真正回答这个问题,但非常重要:在开始重构之前,您应该尽可能现在进行测试。测试的重点是检测你是否破坏了某些东西。

重构是真正有价值的东西,它可以准确地看到某些操作的效果在哪里发生了变化,以及相同的调用在哪里产生了不同的结果。这就是所有这些测试的目的:你想看看你是否破坏了某些东西,你想看到所有无意的变化。

因此,现在对重构后仍应产生相同结果的所有部分进行测试。测试不是针对永远保持不变的完美代码,测试是针对需要更改的代码、需要修改的代码、将要重构的代码。测试是为了确保您的重构确实按照您的意图进行。

于 2010-01-28T02:03:35.867 回答