当前位置: 首页 > news >正文

在 Android 上测试 Kotlin 数据流

文章目录

    • 一 创建虚构数据提供方
    • 二 在测试中断言数据流发出
      • 测试期间持续收集
    • 三 测试 StateFlow
      • 使用 stateIn 创建的 StateFlow

转自:
https://developer.android.google.cn/kotlin/flow/test?hl=zh-cn#producer

与数据流进行通信的单元或模块的测试方式取决于受测对象使用数据流作为输入还是输出

  • 如果受测对象观察到数据流,您可以在虚构依赖项中生成数据流,而这些可以通过测试进行控制
  • 如果单元或模块公开了数据流,您可以读取并验证测试中的数据流所发出的一个或多个数据项

一 创建虚构数据提供方

当受测对象是数据流使用方时,一种常见的测试方法是用虚构实现替换提供方。

class MyFakeRepository : MyRepository {fun observeCount() = flow {emit(ITEM_1)}
}
@Test
fun myTest() {// Given a class with fake dependencies:val sut = MyUnitUnderTest(MyFakeRepository())// Trigger and verify...
}

二 在测试中断言数据流发出

1、某些测试,您只需要检查来自数据流的第一个发出项或有限数量的项

@Test
fun myRepositoryTest() = runTest {// Given a repository that combines values from two data sources:val repository = MyRepository(fakeSource1, fakeSource2)// When the repository emits a valueval firstItem = repository.counter.first() // Returns the first item in the flow// Then check it's the expected itemassertEquals(ITEM_1, firstItem)
}

2、如果该测试需要检查多个值,则调用 toList() 会使数据流等待数据源发出其所有值,然后以列表形式返回这些值

@Test
fun myRepositoryTest() = runTest {// Given a repository with a fake data source that emits ALL_MESSAGESval messages = repository.observeChatMessages().toList()// When all messages are emitted then they should be ALL_MESSAGESassertEquals(ALL_MESSAGES, messages)
}

3、对于需要更复杂地收集数据项或未返回有限数据项的数据流,您可使用 Flow API 选取并转换数据项。

// Take the second item
outputFlow.drop(1).first()// Take the first 5 items
outputFlow.take(5).toList()// Takes the first item verifying that the flow is closed after that
outputFlow.single()// Finite data streams
// Verify that the flow emits exactly N elements (optional predicate)
outputFlow.count()
outputFlow.count(predicate)

测试期间持续收集

在测试中使用虚构实现时,您可以创建一个收集协程,该协程会持续接收 Repository 中的值

class Repository(private val dataSource: DataSource) {fun scores(): Flow<Int> {return dataSource.counts().map { it * 10 }}
}class FakeDataSource : DataSource {private val flow = MutableSharedFlow<Int>()suspend fun emit(value: Int) = flow.emit(value)override fun counts(): Flow<Int> = flow
}

可以创建一个收集协程,该协程会持续接收 Repository 中的值。

@Test
fun continuouslyCollect() = runTest {val dataSource = FakeDataSource()val repository = Repository(dataSource)val values = mutableListOf<Int>()backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {repository.scores().toList(values)}dataSource.emit(1)assertEquals(10, values[0]) // Assert on the list contentsdataSource.emit(2)dataSource.emit(3)assertEquals(30, values[2])assertEquals(3, values.size) // Assert the number of items collected
}

由于此处 Repository 公开的数据流永远无法完成,因此收集它的 toList 调用永远不会返回。
使用 Turbine 库
第三方 Turbine 库提供了一个用于创建收集协程的便捷 API,以及用于测试数据流的其他便捷功能

@Test
fun usingTurbine() = runTest {val dataSource = FakeDataSource()val repository = Repository(dataSource)repository.scores().test {// Make calls that will trigger value changes only within test{}dataSource.emit(1)assertEquals(10, awaitItem())dataSource.emit(2)awaitItem() // Ignore items if needed, can also use skip(n)dataSource.emit(3)assertEquals(30, awaitItem())}
}

三 测试 StateFlow

StateFlow 是一种可观察的数据存储器,可以收集这种存储器来以数据流的形式观察它随时间变化的存储值

以下 ViewModel 会从 Repository 收集值,并在 StateFlow 中将值提供给界面

class MyViewModel(private val myRepository: MyRepository) : ViewModel() {private val _score = MutableStateFlow(0)val score: StateFlow<Int> = _score.asStateFlow()fun initialize() {viewModelScope.launch {myRepository.scores().collect { score ->_score.value = score}}}
}

此 Repository 的虚构实现可能如下:

class FakeRepository : MyRepository {private val flow = MutableSharedFlow<Int>()suspend fun emit(value: Int) = flow.emit(value)override fun scores(): Flow<Int> = flow
}

使用此虚构实现测试 ViewModel 时,您可以从虚构实现发出值,以在 ViewModel 的 StateFlow 中触发更新,然后对更新后的 value 断言:

@Test
fun testHotFakeRepository() = runTest {val fakeRepository = FakeRepository()val viewModel = MyViewModel(fakeRepository)assertEquals(0, viewModel.score.value) // Assert on the initial value// Start collecting values from the RepositoryviewModel.initialize()// Then we can send in values one by one, which the ViewModel will collectfakeRepository.emit(1)assertEquals(1, viewModel.score.value)fakeRepository.emit(2)fakeRepository.emit(3)assertEquals(3, viewModel.score.value) // Assert on the latest value
}

使用 stateIn 创建的 StateFlow

ViewModel 使用 MutableStateFlow 存储 Repository 中的数据流发出的最新值。这是一种常见的模式,通常通过使用 stateIn 运算符以更简单的方式实现,该运算符会将冷数据流转换为热 StateFlow:

class MyViewModelWithStateIn(myRepository: MyRepository) : ViewModel() {val score: StateFlow<Int> = myRepository.scores().stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000L), 0)
}

相关文章:

在 Android 上测试 Kotlin 数据流

文章目录 一 创建虚构数据提供方二 在测试中断言数据流发出测试期间持续收集 三 测试 StateFlow使用 stateIn 创建的 StateFlow 转自&#xff1a; https://developer.android.google.cn/kotlin/flow/test?hlzh-cn#producer 与数据流进行通信的单元或模块的测试方式取决于受测对…...

day43

今日内容 python操作MySQL(重要) SQL注入问题(安全相关的xss,csrf) 视图(了解) 触发器(了解) 事务(重要) 存储过程(了解) 内置函数(了解&#xff0c;很多) 流程控制(了解) 索引(重点) python操作MySQL MySQL本身就是一款c/s架构&#xff0c;有服务端、有客户端&…...

终端管理制度

1、总则 1.1、目的 为规范XXXXX单位员工在使用计算机终端过程中的行为&#xff0c;提高计算机终端的安全性&#xff0c;确保员工安全使用计算机终端&#xff0c;特制定本制度。 1.2、范围 本规定适用于在XXXXX单位使用计算机终端的所有员工&#xff0c;包括内部终端和外部终…...

视频相关学习笔记

YUV 和rgb一样是一种表示色彩的格式&#xff0c;Y表示亮度&#xff0c;UV表示色度&#xff08;U是蓝色投影&#xff0c;V是红色投影&#xff09;&#xff0c;只有Y就是黑白的&#xff0c;所以这个格式的视频图片可以兼容黑白电视&#xff0c;所以彩色电视使用的都是YUV 存储方…...

神经网络中epoch、batch、batchsize区别

目录 1 epoch 2 batch 3 batchsize 4 区别 1 epoch 当数据集中的全部数据样本通过神经网络一次并且返回一次的过程即完成一次训练称为一个epoch。 当我们分批学习时,每次使用过全部训练数据完成一次Forword运算以及一次BP运算,称为完成了一次epoch。 epoch时期 = 所有训练…...

如何将Mysql数据库的表导出并导入到另外的架构

如何将Mysql数据库的表导出并导入到另外的架构 准备一、解决方法1.右键->导出->用mysqldump导出2.注意路径一般为&#xff1a;C:/Program Files/MySQL/MySQL Server 8.0/bin/mysqldump.exe和导出的sql文件位置3.右键->SQL脚本->运行SQL脚本4.找到SQL脚本并点击确定…...

【tio-websocket】9、服务配置与维护—TioConfig

场景 我们在写 TCP Server 时,都会先选好一个端口以监听客户端连接,再创建N组线程池来执行相关的任务,譬如发送消息、解码数据包、处理数据包等任务,还要维护客户端连接的各种数据,为了和业务互动,还要把这些客户端连接和各种业务数据绑定起来,譬如把某个客户端绑定到一…...

数据结构—线性表(下)

文章目录 6.线性表(下)(4).栈与队列的定义和ADT#1.ADT#2.栈的基本实现#3.队列的形式#4.队列的几种实现 (5).栈与队列的应用#1.栈的应用i.后缀表达式求值ii.中缀表达式转后缀表达式 #2.队列的应用 (6).线性表的其他存储方式#1.索引存储#2.哈希存储i.什么是哈希存储ii.碰撞了怎么…...

apisix之插件开发,包含java和lua两种方式

https://download.csdn.net/download/tiantangpw/88475630 有ppt和springboot程序包,可以运行...

【面试经典150 | 链表】合并两个有序链表

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;递归方法二&#xff1a;迭代 写在最后 Tag 【递归】【迭代】【链表】 题目来源 21. 合并两个有序链表 题目解读 合并两个有序链表。 解题思路 一种朴素的想法是将两个链表中的值存入到数组中&#xff0c;然后对数组…...

【linux】麒麟v10安装Redis主从集群(ARM架构)

安装redis单示例的请看&#xff1a;麒麟v10安装Redis&#xff08;ARM架构&#xff09; 安装环境 ​Hostname​IP addressmaster192.168.0.1slave1192.168.0.2slave2192.168.0.3 下载安装包 &#xff08;三台都操作&#xff09; wget https://repo.huaweicloud.com/kunpeng/…...

解决k8s删除名称空间无法强制删除的问题

问题起因&#xff1a;删除k8s名称空间的时候&#xff08;此时名称空间下还有很多pod&#xff09;一直删不掉&#xff0c;被我强行ctrl c了&#xff0c; 问题表象&#xff1a;然后就出现下面这悲催的一幕了&#xff0c;两个名称空间一直处于Terminating了 [rootmaster02 ~]# ku…...

华为---DHCP中继代理简介及示例配置

DHCP中继代理简介 IP动态获取过程中&#xff0c;客户端&#xff08;DHCP Client&#xff09;总是以广播&#xff08;广播帧及广播IP报文&#xff09;方式来发送DHCPDISCOVER和DHCPREQUEST消息的。如果服务器&#xff08;DHCP Server&#xff09;和 客户端不在同一个二层网络(二…...

五、W5100S/W5500+RP2040树莓派Pico<UDP Client数据回环测试>

文章目录 1. 前言2. 协议简介2.1 简述2.2 优点2.3 应用 3. WIZnet以太网芯片4. UDP Client回环测试4.1 程序流程图4.2 测试准备4.3 连接方式4.4 相关代码4.5 测试现象 5. 注意事项6. 相关链接 1. 前言 UDP是一种无连接的网络协议&#xff0c;它提供了一种简单的、不可靠的方式来…...

死锁Deadlock

定义 死锁是指两个或多个线程互相持有对方所需的资源&#xff0c;从而导致它们无法继续执行的情况。如下图所示&#xff0c;现有两个线程&#xff0c;分别是线程A及线程B&#xff0c;线程A持有锁A&#xff0c;线程B持有锁B。此时线程A想获取锁B&#xff0c;但锁B需等到线程B的结…...

【spark客户端】Spark SQL CLI详解:怎么执行sql文件、注释怎么写,支持的文件路径协议、交互式模式使用细节

文章目录 一. Spark SQL Command Line Options(命令行参数)二. The hiverc File1. without the -i2. .hiverc 介绍 三. 支持的路径协议四. 支持的注释类型五. Spark SQL CLI交互式命令六. Examples1. running a query from the command line2. setting Hive configuration vari…...

虹科干货 | HK-TrueNAS版本大揭秘!一文教您如何选择合适的TrueNAS软件

文章来源&#xff1a;虹科网络基础设施 阅读原文&#xff1a;https://mp.weixin.qq.com/s/Iv0zDDmiDgE9vEGlAZs-sg 1&#xff0e;导语 TrueNAS是虹科iXsystems 设计和开发的NAS 操作系统&#xff0c;提供许多功能&#xff0c;例如文件存储、虚拟机 (VM) 和媒体服务器。它基于…...

前端html+css+js实现的2048小游戏,很完善。

源码下载地址 支持&#xff1a;远程部署/安装/调试、讲解、二次开发/修改/定制 逻辑用的是JavaScript&#xff0c;界面用canvas实现&#xff0c;暂时还没有添加动画。 视频浏览地址...

学习通签到

要在Vue中使用H5lock.js&#xff0c;首先需要将H5lock.js引入到项目中。可以通过以下步骤来使用&#xff1a; 1. 将H5lock.js文件保存到项目中的某个目录下&#xff0c;例如src/assets文件夹。 2. 在需要使用H5lock.js的组件中&#xff0c;通过import语句将H5lock.js引入进来…...

target采退、测评养号购物下单操作教程

1.点击右上角的Create account注册账号 2.填写账号信息 3. 进入自己需要购买的商品页面 点击pick it up购买 4. 进入购物车页面选择快递方式和地址后点击 check out按钮 5. 之后会提示绑定XYK&#xff0c;这里我是用虚拟XYK开卡平台进行支付的. 6. 确认订单无误后点击Place you…...

React Native在HarmonyOS 5.0阅读类应用开发中的实践

一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强&#xff0c;React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 &#xff08;1&#xff09;使用React Native…...

2.Vue编写一个app

1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

2023赣州旅游投资集团

单选题 1.“不登高山&#xff0c;不知天之高也&#xff1b;不临深溪&#xff0c;不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...

Android第十三次面试总结(四大 组件基础)

Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成&#xff0c;用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机&#xff1a; ​onCreate()​​ ​调用时机​&#xff1a;Activity 首次创建时调用。​…...

Python Ovito统计金刚石结构数量

大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...