最近我一直在重新思考我的android architecture project,试图使它适应一个更“干净的架构”,特别是suggested by “Uncle Bob”的设计类型。
它涉及到几层抽象、很好的责任隔离和通过依赖注入实现的非常强的依赖反转;这最终导致了一个非常解耦的便携式系统。一个通过单元测试和集成测试进行测试的完美候选者。
在我的Android实现中,我最终有三个不同的模块或层:
-域名:实体、交互器、表示器**(纯java模块)**
-data:(作为存储库向域提供数据)(android库模块)
-介绍:用户界面相关材料、片段、活动、视图等**(安卓应用程序模块)**
所以,我一直在努力寻找iOS生态系统的最佳解决方案,我尝试过创建一个有多个目标的项目来实现同一个解决方案:
-域名:命令行目标(看起来很奇怪,但我认为这是最纯粹的swift目标)
-数据:可可接触框架
-介绍:可可触摸框架
通过这种方法,我可以像使用android模块那样使用这些目标,但我发现的第一个警告是,我需要手动添加每个新文件到依赖目标。
但是我对多目标项目的了解非常有限,我的意思是我从来没有创建过多目标的iOS应用程序,所以我不知道解决方案是否会使用一个框架(可可touch/cocoa)作为目标,而不是域层的命令行模块。
任何想法都将不胜感激。
谢谢!
2条答案
按热度按时间nukf8bse1#
Uncle Bob的Clean Architecture绝对适用于iOS、Swift和Obj-C。架构是语言不可知论者。Uncle Bob自己主要用Java编写代码,但在他的演讲中很少提到Java。他所有的幻灯片甚至没有显示任何代码。这是一种适用于任何项目的架构。
为什么我这么肯定?因为我已经学习MVC、MVVM、ReactiveCocoa和Clean Architecture两年了。到目前为止,我最喜欢Clean Architecture。我通过将7个苹果示例项目转换为使用Clean Architecture来测试它。我专门使用这种方法一年多了。每次都效果更好。
其中一些好处是:
我们还添加了一个路由器组件,这样我们就可以使用多个故事板。没有更多的冲突。
编写单元测试也大大简化了,因为我只需要测试边界上的方法,而不需要测试私有方法。最重要的是,我甚至不需要任何模拟框架,因为编写自己的模拟和存根变得微不足道。
我在Clean Swift上写了我过去两年研究iOS架构的经验,我还整理了一些Xcode模板来生成所有的清洁架构组件,以节省大量的时间。
这是一个非常好的问题,需要一个很长很详细的答案。
始终牢记VIP循环。在这种情况下,
doSomethingOnLoad()
方法不是一个 * boundary * 方法。相反,它是一个仅在CreateOrderViewController
中调用的 * internal * 方法。在单元测试中,我们测试单元的预期行为。我们给出输入,观察输出,然后将输出与预期进行比较。是的,我本可以让
doSomethingOnLoad()
成为一个私有方法。但是我选择了不这样做。Swift的目标之一就是让开发人员编写代码变得更容易。所有的边界方法都已经在 * input * 和 * output * 协议中列出了。真的没有必要在类中添加额外的私有修饰符。现在,我们确实需要以某种方式测试"
CreateOrderViewController
应该在加载此请求数据时执行某些操作"的行为,对吗?如果doSomethingOnLoad()
是私有方法,我们不能调用它,我们怎么测试呢?你调用viewDidLoad()
。viewDidLoad()
方法是边界方法。哪个边界?用户和视图控制器之间的边界!用户对设备做了一些操作,使其加载另一个屏幕。那么我们如何调用viewDidLoad()
呢?您可以这样做:简单地调用
createOrderViewController.view
属性会导致viewDidLoad()
被调用,很久以前我从某人那里学到了这个技巧,但是Natasha The Robot最近也提到了它。当我们决定测试什么时,只测试边界方法是非常重要的。如果我们测试一个类的每一个方法,测试就会变得极其脆弱。我们对代码所做的每一个修改都会破坏很多很多测试。很多人因此而放弃。
或者,可以这样想,当你问如何模仿
CreateOrderRequest
时,首先问doSomethingOnLoad()
是否是一个边界方法,你应该为它编写test。如果不是,那是什么?在这个例子中,边界方法实际上是viewDidLoad()
。输入是"当这个视图加载时"。输出是"用这个请求对象调用这个方法"。这是使用CleanSwift的另一个好处。所有的边界方法都列在文件的顶部,分别使用明确命名的协议
CreateOrderViewControllerInput
和CreateOrderViewControllerOutput
。你不需要去别处找!想一想如果你测试
doSomethingOnLoad()
会发生什么。你模拟请求对象,然后Assert它等于你期望的请求对象。你在模拟某个东西并比较它。它就像assert(1, 1)
而不是var a=1; assert(a, 1)
。有什么意义呢?太多测试。太脆弱。现在,你需要模拟
CreateOrderRequest
。在你验证视图控制器组件可以生成正确的CreateOrderRequest
之后,当你测试CreateOrderInteractor
的doSomething()
边界方法时,你可以使用接口依赖注入来模拟CreateOrderRequest
。简而言之,单元测试不是测试类的每个单元,而是将类作为一个单元进行测试。
这是一种心态转变。
希望能有所帮助!
我有3个系列的草稿文章在WordPress上不同的主题:
1.深入了解Clean Swift的每个组件
1.如何将复杂的业务逻辑分解为工作者和服务对象。
1.在Clean Swift iOS架构中编写测试
你想先听哪一个?我应该增加测试的系列吗?
8ljdwjyq2#
在我看来,清洁架构是一套想法,规则,原则...使代码更好。
Android Clean Architecture(https://stackoverflow.com/a/61126623/4770877)
通过这种方法,我可以像使用android模块那样使用这些目标。
您可以创建目标About(https://stackoverflow.com/a/59215808/4770877)(应用程序目标或框架目标...),但这取决于您的需要
如果你读费尔南多·塞哈斯的《Architecting Android...Reloaded》
您可能已经看到我使用Android模块来表示架构中涉及的每一层。
讨论中反复出现的一个问题是:为什么?答案很简单...错误的技术决定
其思想是,不必使用某些构建组件来实现Clean Architecture