[Android]单元测试和模块测试

在 Kotlin 开发中,单元测试和模块测试(有时也称为组件测试或服务测试)是两种关键的测试方法,它们帮助开发者确保代码的各个部分独立和整体上都按预期工作。

1.单元测试

单元测试是测试软件应用中最小单元(通常是方法或函数)的过程。它的目标是验证这些单元在隔离的环境中的行为是否符合预期。

优点

  • 快速执行。
  • 帮助开发者识别和修复问题的精确位置。
  • 通过测试用例作为文档,可以增加代码的可读性和可维护性。

常用工具

  • JUnit: Java和Kotlin中最流行的测试框架。
  • MockK: 为Kotlin特别设计的模拟库,支持协程和扩展函数的模拟。
  • Spek: 使用Kotlin DSL的基于规格的测试框架。

示例 1: 简单的单元测试

假设我们有一个简单的 Calculator 类:

class Calculator {fun add(a: Int, b: Int): Int = a + bfun multiply(a: Int, b: Int): Int = a * b
}

为这个类编写单元测试:

import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.assertEqualsclass CalculatorTest {private val calculator = Calculator()@Testfun `add should correctly add two numbers`() {assertEquals(5, calculator.add(2, 3), "Adding 2 and 3 should equal 5")}@Testfun `multiply should correctly multiply two numbers`() {assertEquals(6, calculator.multiply(2, 3), "Multiplying 2 by 3 should equal 6")}
}

示例 2: 使用 MockK 模拟依赖

假设我们有一个依赖外部服务的 UserService 类:

class UserService(private val userApi: UserApi) {fun getUserEmail(userId: Int): String? {val user = userApi.fetchUserById(userId)return user?.email}
}data class User(val id: Int, val name: String, val email: String)
interface UserApi {fun fetchUserById(userId: Int): User?
}

为 UserService 编写单元测试,使用 MockK 模拟外部 API:

import io.mockk.every
import io.mockk.mockk
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.assertEqualsclass UserServiceTest {private val userApi = mockk<UserApi>()private val userService = UserService(userApi)@Testfun `getUserEmail returns correct email`() {val user = User(1, "John Doe", "john@example.com")every { userApi.fetchUserById(1) } returns userval email = userService.getUserEmail(1)assertEquals("john@example.com", email)}@Testfun `getUserEmail returns null if user not found`() {every { userApi.fetchUserById(any()) } returns nullval email = userService.getUserEmail(99)assertEquals(null, email)}
}

2.模块测试

模块测试或组件测试通常涉及一个模块或多个紧密相关的模块(如一个类及其依赖)。这种测试可能涉及数据库、文件系统、网络或其他外部依赖的模拟。

优点

  • 验证模块间的集成是否正确。
  • 检查模块与外部系统的交互。
  • 找到可能在单元测试中被忽略的问题。

常用工具

  • JUnit 或 TestNG: 用于编写和执行测试。
  • MockK: 模拟外部依赖。
  • Testcontainers: 提供真实的外部服务测试环境,如使用Docker容器的数据库。

示例: 模块测试

假设我们有一个 OrderService 类,它依赖于 OrderRepository 和 PaymentService

class OrderService(private val orderRepository: OrderRepository, private val paymentService: PaymentService) {fun processOrder(orderId: Int, paymentDetails: PaymentDetails): Boolean {val order = orderRepository.findById(orderId) ?: return falsereturn paymentService.processPayment(order, paymentDetails)}
}interface OrderRepository {fun findById(orderId: Int): Order?
}interface PaymentService {fun processPayment(order: Order, paymentDetails: PaymentDetails): Boolean
}data class Order(val id: Int, val amount: Double)
data class PaymentDetails(val method: String, val amount: Double)

为 OrderService 编写模块测试:

import io.mockk.every
import io.mockk.mockk
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Assertions.assertFalseclass OrderServiceTest {private val orderRepository = mockk<OrderRepository>()private val paymentService = mockk<PaymentService>()private val orderService = OrderService(orderRepository, paymentService)@Testfun `processOrder returns true when payment is successful`() {val order = Order(1, 100.0)val paymentDetails = PaymentDetails("credit",100.0)every { orderRepository.findById(1) } returns orderevery { paymentService.processPayment(order, paymentDetails) } returns trueval result = orderService.processOrder(1, paymentDetails)assertTrue(result, "Order processing should succeed when payment is successful")}@Testfun `processOrder returns false when order not found`() {every { orderRepository.findById(any()) } returns nullval result = orderService.processOrder(99, PaymentDetails("credit", 50.0))assertFalse(result, "Order processing should fail when order is not found")}@Testfun `processOrder returns false when payment fails`() {val order = Order(1, 100.0)val paymentDetails = PaymentDetails("debit", 100.0)every { orderRepository.findById(1) } returns orderevery { paymentService.processPayment(order, paymentDetails) } returns falseval result = orderService.processOrder(1, paymentDetails)assertFalse(result, "Order processing should fail when payment fails")}
}

3.断言方法

在 Kotlin 开发中,单元测试和模块测试通常使用测试框架,如 JUnit,Kotlin Test,或 Spek 等。这些框架提供了一系列的断言方法,这些方法是用来验证代码的行为是否符合预期的关键组件。我将重点介绍 JUnit 和 Kotlin Test 中常用的断言方法。

(1).JUnit 断言方法

JUnit 是 Java 和 Kotlin 中最常用的测试框架之一。JUnit 5 提供了一个 Assertions 类,其中包含多种静态方法用于断言测试结果。

基本断言
  • assertEquals(expected, actual, message): 验证两个值是否相等。
  • assertNotEquals(unexpected, actual, message): 验证两个值是否不等。
  • assertTrue(condition, message): 验证条件是否为真。
  • assertFalse(condition, message): 验证条件是否为假。
  • assertNull(value, message): 验证对象是否为 null
  • assertNotNull(value, message): 验证对象是否非 null
对象和类断言
  • assertSame(expected, actual, message): 验证两个引用是否指向同一个对象。
  • assertNotSame(unexpected, actual, message): 验证两个引用是否不指向同一个对象。
数组和集合断言
  • assertArrayEquals(expected, actual, message): 验证两个数组是否相等。
异常断言
  • assertThrows(exceptionType, executable, message): 验证预期的异常是否被抛出。
组合断言
  • assertAll(executables): 同时执行多个断言,只有当所有断言都通过时,测试才会通过。
示例
import org.junit.jupiter.api.Assertions.*
import org.junit.jupiter.api.Testclass AssertionsExample {@Testfun testAssertions() {assertEquals(4, 2 + 2, "Addition should work")assertTrue(5 > 2, "5 is greater than 2")assertAll("multiple",{ assertNotNull("Hello", "Should not be null") },{ assertThrows(ArithmeticException::class.java, { val result = 2 / 0 }, "Should throw ArithmeticException") })}
}

(2).Kotlin Test 断言方法

Kotlin Test 是另一种专为 Kotlin 设计的测试库,它提供了一些额外的断言功能。

基本断言
  • shouldBe: 用于任何类型,比较是否相等。
  • shouldNotBe: 用于任何类型,比较是否不等。
  • shouldBeNull: 检查对象是否为 null
  • shouldNotBeNull: 检查对象是否非 null
  • shouldThrow: 检查是否抛出异常。
集合断言
  • shouldContain: 检查集合是否包含元素。
  • shouldNotContain: 检查集合是否不包含元素。
字符串断言
  • shouldStartWith: 检查字符串是否以特定前缀开始。
  • shouldEndWith: 检查字符串是否以特定后缀结束。
示例
import io.kotest.matchers.shouldBe
import io.kotest.matchers.nulls.shouldBeNull
import io.kotest.matchers.string.startWith
import io.kotest.core.spec.style.StringSpecclass KotlinTestExample : StringSpec({"addition works" {(2 + 2) shouldBe 4}"null checks" {val str: String? = nullstr.shouldBeNull()}"string should start with" {"hello world".shouldStartWith("hello")}
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/321390.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

动手写一个简单的Android 表格控件支持固定列

Android 动手写一个简洁版表格控件 简介 源码已放到 Github Gitee 作为在测绘地理信息行业中穿梭的打工人&#xff0c;遇到各种数据采集需求&#xff0c;既然有数据采集需求&#xff0c;那当然少不了数据展示功能&#xff0c;最常见的如表格方式展示。 当然&#xff0c;类似…

一机游领航旅游智慧化浪潮:借助前沿智能设备,革新旅游服务效率,构建高效便捷、生态友好的旅游服务新纪元,开启智慧旅游新时代

目录 一、引言 二、一机游的定义与特点 &#xff08;一&#xff09;一机游的定义 &#xff08;二&#xff09;一机游的特点 三、智能设备在旅游服务中的应用 &#xff08;一&#xff09;旅游前的信息查询与预订支付 &#xff08;二&#xff09;旅游中的导航导览与互动体…

stm32之hal库串口中断和ringbuffer的结合

前言 结合hal库封装的中断处理函数使用rt-thread内部的rt-ringbuffer数据结构源码改造hal库串口部分的源码&#xff0c;将内部静态方法变为弱引用的函数&#xff0c;方便重写标志位采用信号量或变量的两种方式&#xff0c;内部数据分配方式采用动态和静态两种方式 hal库部分串…

开箱子咸鱼之王H5游戏源码_内购修复优化_附带APK完美运营无bug最终版__GM总运营后台_附带安卓版本

内容目录 一、详细介绍二、效果展示2.效果图展示 三、学习资料下载 一、详细介绍 1.包括原生打包APK&#xff0c;资源全部APK本地化&#xff0c;基本上不跑服务器宽带 2.优化后端&#xff0c;基本上不再一直跑内存&#xff0c;不炸服响应快&#xff01; 3.优化前端&#xff0c…

【再探】设计模式—适配器、装饰及外观模式

结构型设计模式是用于设计对象和类之间关系的一组设计模式。一共有7种&#xff1a;适配器模式、装饰器模式、外观模式、桥接模式、组合模式、享元模式及代理模式。 1 适配器模式 需求&#xff1a;在软件维护阶段&#xff0c;已存在的方法与目标接口不匹配&#xff0c;需要个中…

【DeepLearning.AI】吴恩达系列课程——使用ChatGPT API构建系统(持续更新中——)

目录 前言一、Language Models, the Chat Format and Tokens&#xff08;LLM&#xff0c;交互形式&#xff09;1-1、加载api-key1-2、使用辅助函数&#xff08;即指令调整LLM&#xff09;1-2、使用辅助函数&#xff08;聊天格式&#xff09;1-3、辅助函数修改&#xff08;输出字…

2024年船舶、机械制造与海洋科学国际会议(ICSEMMS2024)

2024年船舶、机械制造与海洋科学国际会议&#xff08;ICSEMMS2024&#xff09; 会议简介 我们诚挚邀请您参加将在重庆隆重举行的2024年国际造船、机械制造和海洋科学大会&#xff08;ICSEMMS024&#xff09;。作为一项跨学科和跨学科的活动&#xff0c;本次会议旨在促进造船…

北京大学-知存科技存算一体联合实验室揭牌,开启知存科技产学研融合战略新升级

5月5日&#xff0c;“北京大学-知存科技存算一体技术联合实验室”在北京大学微纳电子大厦正式揭牌&#xff0c;北京大学集成电路学院院长蔡一茂、北京大学集成电路学院副院长鲁文高及学院相关负责人、知存科技创始人兼CEO王绍迪、知存科技首席科学家郭昕婕博士及企业研发相关负…

深入Django:用户认证与权限控制实战指南

title: 深入Django&#xff1a;用户认证与权限控制实战指南 date: 2024/5/7 18:50:33 updated: 2024/5/7 18:50:33 categories: 后端开发 tags: AuthDecoratorsPermissionsGuardianRESTAuthSessionMgmtMFA 第1章&#xff1a;入门Django与设置 1.1 Django安装与环境配置 在…

大数据分析入门之10分钟掌握GROUP BY语法

前言 书接上回大数据分析入门10分钟快速了解SQL。 本篇将会进一步介绍group by语法。 基本语法 SELECT column_name, aggregate_function(column_name) FROM table_name GROUP BY column_name HAVING condition假设我们有students表&#xff0c;其中有id,grade_number,class…

Golang | Leetcode Golang题解之第70题爬楼梯

题目&#xff1a; 题解&#xff1a; func climbStairs(n int) int {sqrt5 : math.Sqrt(5)pow1 : math.Pow((1sqrt5)/2, float64(n1))pow2 : math.Pow((1-sqrt5)/2, float64(n1))return int(math.Round((pow1 - pow2) / sqrt5)) }

docker jenkins 部署springboot项目

1、创建jenkins容器 1&#xff0c;首先&#xff0c;我们需要创建一个 Jenkins 数据卷&#xff0c;用于存储 Jenkins 的配置信息。可以通过以下命令创建一个数据卷&#xff1a; docker volume create jenkins_data启动 Jenkins 容器并挂载数据卷&#xff1a; docker run -dit…

【区块链】智能合约简介

智能合约起源 智能合约这个术语至少可以追溯到1995年&#xff0c;是由多产的跨领域法律学者尼克萨博&#xff08;NickSzabo&#xff09;提出来的。他在发表在自己的网站的几篇文章中提到了智能合约的理念。他的定义如下&#xff1a;“一个智能合约是一套以数字形式定义的承诺&a…

上位机图像处理和嵌入式模块部署(树莓派4b镜像烧录经验总结)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 陆陆续续也烧录了好多次树莓派的镜像了&#xff0c;这里面有的时候很快&#xff0c;有的时候很慢。特别是烧录慢的时候&#xff0c;也不知道是自己…

基于FPGA的DDS波形发生器VHDL代码Quartus仿真

名称&#xff1a;基于FPGA的DDS波形发生器VHDL代码Quartus仿真&#xff08;文末获取&#xff09; 软件&#xff1a;Quartus 语言&#xff1a;VHDL 代码功能&#xff1a; DDS波形发生器VHDL 1、可以输出正弦波、方波、三角波 2、可以控制输出波形的频率 DDS波形发生器原理…

用Docker 创建并运行一个MySQL容器

可以在DockerHub官网上荡:mysql - Official Image | Docker Hub 指令是:docker pull mysql; 因为文件比较大可能时间比较长&#xff0c;我是跟着黑马的课走的 课程提供的有文件&#xff0c;我就用已有的资源了。 在tmp目录里放入mysql.tar包 然后cd进去 输入指令:docker lo…

STM32——WWDG(窗口看门狗)

技术笔记&#xff01; 1.WWDG&#xff08;窗口看门狗&#xff09;简介 本质&#xff1a;能产生系统复位信号和提前唤醒中断的计数器。 特性&#xff1a; 递减的计数器&#xff1b; 当递减计数器值从 0x40减到0x3F时复位&#xff08;即T6位跳变到0&#xff09;&#xff1b; …

FTP协议与工作原理

一、FTP协议 FTP&#xff08;FileTransferProtocol&#xff09;文件传输协议&#xff1a;用于Internet上的控制文件的双向传输&#xff0c;是一个应用程序&#xff08;Application&#xff09;。基于不同的操作系统有不同的FTP应用程序&#xff0c;而所有这些应用程序都遵守同…

update_min_vruntime()流程图

linux kernel scheduler cfs的update_min_vruntime() 看起来还挺绕的。含义其实也简单&#xff0c;总一句话&#xff0c;将 cfs_rq->min_vruntime 设置为&#xff1a; max( cfs_rq->vruntime, min(leftmost_se->vruntime, cfs_rq->curr->vruntime) )。 画个流…

超疏水TiO₂纳米纤维网膜的良好性能

超疏水TiO₂纳米纤维网膜是一种具有特殊性能的材料&#xff0c;它结合了TiO₂的光催化性能和超疏水表面的自清洁、防腐、防污等特性。这种材料在防水、自清洁、油水分离等领域具有广阔的应用前景。 制备超疏水TiO₂纳米纤维网膜的过程中&#xff0c;通过精确控制纺丝溶液的成分…