188be188博金宝电子体育频道;t金宝搏官网Okcupid提高了带着假货和工厂的Android可测试性

许多公司的Codebases存在遗留代码。通常在内部,存在在开发过程中导致障碍的反模式。

我最近添加了我的第一个分析活动,作为我刚刚完成的一些功能工作的一部分。我偶然发现了一些意料之外的问题,这些问题是错误模式的结果。在本文中,我将向您展示如何使用抽象和改进的可测试性克服这些问题。

空调

我们有一个调用的特征或流量特定类sessionmetrics..它包含所有必要的部分,用于发送与我们的用户会话相关的分析事件。其大部分方法将数据作为输入将数据带到,然后创建并发送特定于我们的分析库的事件。它还定义了我们通过我们的活动发送的通用值。

Object Sessionmetrics:baseMetrics(){const val convo_status =“会话状态”有趣FireSelectedMsg(/ *大量Params * /){//创建事件FireeVent(事件)}}

sessionmetrics.以上从父类扩展粪便仪.父元素非常小,是直接调用分析库的包装器。它还包含一个方便的方法,用于创建特定于我们的分析库的事件。

以下是一个例子粪便仪好像。

开放类粪便{fun firelevent(事件:事件){val instance = symenticstool.getInstance()}}}

问题

作为我们工作的一部分,我们需要从ViewModel添加新的分析事件。天真地,我们符合上面的模式。代码正如预期的那样,但我们很快就会迎接一个破碎的单位测试。我们的静态构造正直接呼叫我们的分析库,因此我们的视图模型测试失败了。

这条线val instance = symilticstool.getInstance()上面的例子引起了这个问题。我们的AnalyticsTool从来没有打算在JVM中运行,因此破坏了我们的单元测试。我们能做什么呢?我们不能就这样不管。

我们的目标是什么?

至少,我们的变化不应破坏测试。尽管如此,我们希望通过测试除了不打破现有测试之外,我们希望通过测试进行验证。让我们的目标高,看看我们可以想出什么!

从界面开始

让我们开始创建一个接口,该接口将定义要发送到我们的分析客户端的值。

interface SessionMetrics {fun fireSelectedMsg(inboxSizeProperty: Int?, targetUserId:字符串?, matchedUser:用户?, initialNWays: Int?)}

我们正在呼叫我们的界面sessionmetrics.它将有我们的活动方法fireSelectedMsg ()这将为我们的分析活动收集所有必需的数据。

创建一个实施

Class AnalyticsLibSessionMetrics:sessionmetrics,basemetrics(){override fun fireceselectedmsg(inboxsizeproperty:int?,targetUserID:String ?,匹配用户:UsiteNnways:Int?){//从我们传递的Data Firedvent中创建我们的Analytics库特定事件//(分析libevent)}}

然后像上面那样创建具体的实现并命名AnalyticsLibSessionMetrics.名称应反映此具体实施方式的哪些分析库。在这种情况下它是AnalyticsLib.它实现了我们的sessionmetrics.接口上面除了实用程序粪便仪如果你用的是Firebase,那就是FirebaseSessionMetrics

我们现在可以将新创建​​的类传递给我们的视图:

MessageThreadViewModel(AnalyticsLibSessionMetrics())

使用假修复测试

让我们通过创建代表我们声明的界面的假设来获得测试并再次运行。

FakeSessionMetrics类:SessionMetrics {override fun fireSelectedMsg(inboxSizeProperty: Int?, targetUserId:字符串?, matchedUser:用户?, initialNWays: Int?){//什么都不做}}

使用我们的假声明,我们可以从测试中创建我们的视图:

val fakeSessionMetrics = fakeSessionMetrics ()

现在我们的测试再次工作,因为我们不试图拨打我们的分析库。感觉像我们可以做得更好!让我们验证实际调用的事件。

验证使用假

让我们将实例变量添加到我们的fakessionmetrics.

class faxessionmetrics:sessionmetrics {var selectedmsgeventfired = false覆盖有趣fireselectedmsg(//大量参数){selectsmegeventfired = true}}

实例变量selectedMsgEventFired当我们的假事件方法被调用时被设为true。然后,我们可以通过测试验证我们的fireSelectedMsg ()方法按我们的要求调用。

为了(fakeSessionMetrics.selectedMsgEventFired) .isTrue ()

有些事情还是不对

我们的参数fireSelectedMsg ()方法并不是我们传递给分析客户的价值。我们对数据进行一些处理,以获得一些值,然后发送给我们的分析客户端。代码库中的当前模式将把这个处理逻辑放在ViewModel中。我现在的设计在我们新创建的设计中有sessionmetrics.它没有真正属于任何一种。

为什么它不属于任何一个?

ViewModel不应该负责处理发送到分析层的数据。它增加了ViewModel的职责,使我们更难验证此处理中的逻辑。

如果我们在我们的助手的具体实施中将这个处理逻辑放入sessionmetrics.,我们就无法进行测试。我们会遇到测试失败的原始问题,因为我们直接调用了分析库。处理逻辑与我们的具体实现有什么关系吗?

数据作为类型

让我们准确地查看我们将发送到我们的分析客户端。

val hasread:boolean,val targetuserid:string?,val yeyindays:int,val inboxsize:int

接下来,我们可以创建一个数据类来表示这些值。

数据类SelectedMessageEvent(val hasRead: Boolean, val targetUserId: String?, val ageInDays: Int, val inboxSize: Int)

我们的sessionmetrics.接口现在可以更改。

interface sessionmetrics {fun fireselectedmsg(selectedMessageEvent:SelectedMessageEvent)}

这简化了界面并从我们的处理逻辑中解耦了我们的分析库。我们现在是究竟是关于我们的分析库对此活动的期望。

处理逻辑

我们可以将处理逻辑与数据类关联起来,因为它们在逻辑上是一起的。我们可以附加一个静态方法从()到我们的数据类,像:

数据类SelectedMessageEvent(val hasread:boolean,val targetuserid:string?,val yegeindays:int,val inboxsize:int){companion对象{from(inboxsizeproperty:int?,targetUserId:string ?, matchedUser:UnitedUnways:Inte?):SelectedMessageEvent {//处理逻辑}}}

我们的ViewModel调用如下:

val event = SelectedMessageEvent.from(inSize, userId, matchedUser, nWays)

这一切意味着什么

我们的ViewModel现在减少了责任。它创造了一个事件,尽管它不知道如何去做。它将事件发送到它不知道具体实现的接口。这一切都导致了测试的改进。我们现在可以在测试时断言我们的分析层被调用了。

分析层现在正在使用我们的自定义数据类,其中派生值不需要处理。我们现在明确地了解这本层需要什么。如果在将来,我们希望替换我们的分析库或添加其他实施,它只需要仅用于消耗我们的新数据类。

用于创建事件的处理逻辑现已被隔离并且可以进行测试。我们可以提供广泛的输入,并验证事件数据类是在我们期望时生成的。

我们的测试现在有效,我们可以在ViewModel中验证正确的行为,我们可以验证我们的事件数据类是否已正确创建。

我希望你喜欢这篇文章,请随时联系我推特

有兴趣为OkCupid工作吗?188bet金宝搏官网我们正在招聘

最初出版https://tech.188bet金宝搏官网okcupid.com.2020年7月27日。

188bet金宝搏官网Okcupid Tech Blog.

阅读OkCupid工程团队每天连接数百万人的188bet金宝搏官网故事

写的

Brian对Android应用程序的热情已经持续了10多年。188博金宝电子体育频道他喜欢在会议和聚会上谈论Android。188博金宝电子体育频道

188bet金宝搏官网Okcupid Tech Blog.

188bet金宝搏官网Okcupid的工程团队负责每天匹配数百万人。阅读Okcupid Tech Blog上的故事188bet金宝搏官网

写的

Brian对Android应用程序的热情已经持续了10多年。188博金宝电子体育频道他喜欢在会议和聚会上谈论Android。188博金宝电子体育频道

188bet金宝搏官网Okcupid Tech Blog.

188bet金宝搏官网Okcupid的工程团队负责每天匹配数百万人。阅读Okcupid Tech Blog上的故事188bet金宝搏官网