我对单元测试的理解

我对单元测试的理解 保证测试的代码符合编写时的预期 目前为止,我还没有系统的学习过测试领域的知识,但是测试对于研发岗来说是重要的。测试在我的日常工作中主要是起到程序逻辑校验的作用,作为研发来说,自己做的单元测试的目的主要在于程序逻辑,而不是业务逻辑。也就是说,单元测试能保证通过单元测试的代码一定是符合我的预期的,而我的预期本身是不是有问题没法通过单元测试校验,需要集成测试以及专业的测试团队进行测试。 单元测试帮助我快速复现bug 在实际生产过程中,我的单元测试足够多,覆盖面足够广,那么出了问题的时候就可以快速定位到出错代码的单元测试。这样修改代码,就可以针对单元测试来进行修改。当然,这里也会出现,bug出现了却没有制定的单元测试,这时就可以添加单元测试,在修复bug的同时丰富单元测试用例。我称之为基于单元测试的敏捷开发。 单元测试帮助代码重构 这有两方面,第一方面是有了单元测试,在代码重构时就能可以保证代码的输入和输出不会出问题,那就可以放心大胆的一步一步重构。第二方面,单元测试也能保证代码质量,因为越小的代码,耦合越低的代码越容易进行单元测试。有的一些代码在写单元测试的时候会发现根本无从下手,这就是很明显的代码坏味道。 单元测试帮助阅读和理解旧代码 我发现这一点很少有人提及,因为单元测试一般都是测试一些比较关键的代码,而且输入和输出都会明确列举出来。如果源代码里有单元测试,那么读单元测试就能很清晰的了解到这一块代码的作用是什么。而如果没有单元测试,又有一块代码的逻辑不是很清晰,那么也可以通过补充单元测试的方式来搞懂代码。说白了,单元测试就是可以将一块代码简化成输入->输出这种形式,更易于人脑解析。 研发的单元测试比重 很多人不想写单元测试,是觉得单元测试时间太长。其实单元测试的好处大家都知道,如果给予更多的开发周期,相信更多人会花时间在单元测试上。其实这里关键的问题不止单元测试值不值得做,还有单元测试耗费的时间到底长不长。单元测试一定值得做,上面提到的好处在整体上一定会减少开发时间。而单元测试耗费的时间到底长不长呢?这就要提到一个误区了,有不少人是把单元测试也当作代码来写,这并没有太多问题,但是单元测试是一种工具,那么使用这种工具就一定是越简单越快越好,直白点就是有轮子就用轮子,代码越简单越好。比如写java的单元测试,如果不引用单元测试框架,但确实折磨,引入了框架再加上一些mock工具就很更加简单,而如果再使用一些辅助语言比如groovy或者scala,单元测试就会变得十分简单,就是在程序编写时顺手的一个工作。 Spock单元测试推荐 我再尝试了一些单元测试框架和mock工具之后,目前在写java程序时稳定使用的是spock测试框架,这时一个基于groovy的单元测试框架,groovy和java代码可以无缝接入,所以我的代码一般都是主程序用java写,测试程序用groovy写。 简单的spock测试程序大概长这样: class PropertyCopierTest extends Specification { def "CopyBeanProperties"() { given: def sourceBean = new TestProperty("beanOne", 100) def destinationBean = new TestProperty() when: PropertyCopier.copyBeanProperties(TestProperty.class, sourceBean, destinationBean) then: destinationBean.with { name == "beanOne" id == 100 } } } spock的教程网上有很多,我就不累述了: Spock单元测试框架介绍以及在美团优选的实践 用Groovy更迅速地对Java代码进行单元测试 Introduction to Testing with Spock and Groovy 单元测试和Mock工具中的一些通用概念 mock mock就是直接通过类创建一个对象,这个对象的返回值是模拟出来的也就是程序调用到指定方法就返回你事先定义好的值。 比如用Mockito框架mock: //模拟PersonDao对象 mockDao = mock(PersonDao.class); when(mockDao.getPerson(1)).thenReturn(new Person(1, "Person1")); when(mockDao....

November 25, 2022 · 1 min

技术文章归总(1)

单元测试 使用Junit+Mockito实践单元测试 Spock单元测试框架介绍以及在美团优选的实践 腾讯新闻的单元测试总结 用Groovy更迅速地对Java代码进行单元测试 Linux 通过inode删除乱码文件 Spark 美团技术团队Spark优化基础篇 美团技术团队Spark优化高级篇 SparkSql与hive on spark与spark on hive的关系 不要滥用spark repartition hiveql的distribute by Spark Thrift Server与Hive Server2的区别详解 如何管理spark的分区 图数据库平台建设 美团图数据库平台建设 OPPO图数据库平台建设 算法 滑动窗口算法

October 26, 2022 · 1 min

Windows下安装运行hadoop的几个要点

hadoop2.7.1要使用的jdk必须是64位的,使用javac命令,如果是64位的jdk会有64的字眼出现,没有就不是64位的,这一点很关键,32位的sdk是运行不了hadoop2.7.1的。 hadoop的压缩包解压需要管理员权限 环境变量里面要添加HADOOP_HOME,path路径里面要增加hadoop安装目录下的bin 要修改Hadoop-2.7.1/etc/hadoop/hadoop-env.cmd里面java的路径,JAVA_HOME=%JAVA_HOME%,理论上如果环境变量里面设置了JAVA_HOME也就不需要改了 伪集群运行,配置文件哪些是必须填的,哪些是选择,有什么作用? <!--core-site.xml--> <configuration> <property> <!--这是选择使用默认的文件系统--> <name>fs.defaultFS</name> <!--使用localhost,这样hdfs的客户端连接端口会默认启动在localhost:8020上,才能在本机通过hadoop fs命令以及直接用java api 访问--> <value>hdfs://localhost/</value> </property> </configuration> <!--mapred-site.xml--> <configuration> <property> <name>mapreduce.framework.name</name> <value>yarn</value> </property> </configuration> <!--hdfs-site.xml--> <configuration> <property> <!--配置副本数--> <name>dfs.replication</name> <value>1</value> </property> <!--下面的namenode和datanode路径是可选的,主要是为了指定namenode和datanode的路径,如果不指定的话,hadoop会在默认路径下生成这些文件,好像是直接在根目录下生成(反正不在安装目录下,要看一下日志文件),指定路径就要在相对于的位置下(这里是安装目录下)创建相对应的目录--> <property> <name>dfs.namenode.name.dir</name> <value>/hadoop-2.7.1/data/namenode</value> </property> <property> <name>dfs.datanode.data.dir</name> <value>/hadoop-2.7.1/data/datanode</value> </property> </configuration> <!--yarn-site.xml--> <configuration> <property> <name>yarn.nodemanager.aux-services</name> <value>mapreduce_shuffle</value> </property> </configuration> 执行hdfs namenode –format,在bin目录下,bin目录已经设在path里了,应该在哪里都可以直接使用 执行start-all.cmd,在sbin目录下 会启动四个服务,使用jps可以查看 四个服务分别是namenode的服务,datanode的服务,yarn里面的两个服务,一个负责资源管理,一个负责节点管理

September 29, 2022 · 1 min

使用vscode调试c

在vscode下创建tasks.json文件,该文件会被vscode用来执行生成可执行文件的操作。 { "version": "2.0.0", "tasks": [ { "label": "build c", "type": "shell", "command": "cc", "args": [ "-std=c99", "-Wall", "-ledit", "-lm", "-g", "${workspaceFolder}/**.c", "-o", "${workspaceFolder}/${fileBasenameNoExtension}.out" ], "group": "build" }, ] } Command 和 args 是主要的参数,如何生成可执行文件就如何编写。 ${workspaceFolder}表示工作目录 ${fileBasenameNoExtension}如其名表示去掉后缀的文件名 创建launch.json文件,该文件会被vscode用来执行debug操作。 { "version": "0.2.0", "configurations": [ { "preLaunchTask": "build c", "name": "Launch C", "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/${fileBasenameNoExtension}.out", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], "externalConsole": true, "MIMode": "lldb", } ] } preLaunchTask填写生成调试文件的task的label。...

September 28, 2022 · 1 min

数据密集型应用学习笔记

第一部分:适用于所有数据系统的基本思想 第1章:术语与方法 数据库 高速缓存 索引:按关键字搜索数据并支持各种过滤 流式处理:持续发送消息至另一个进程,处理采用异步方式 批处理:定期处理大量的累积数据 设计数据系统时会遇到的问题 当系统内出现了局部失效时,如何确保数据的正确性与完整性? 当发生系统降级时,该如何为客户提供一致的良好表现? 负载增加时,系统如何扩展? 友好的服务API该如何设计? 目标 可靠性 硬件错误、软件错误、人为错误 可扩展性 本系统的负载是什么?(每秒请求处理次数?同时活动用户数量?平均值?峰值?) 负载增加但系统资源不变,系统性能会发生什么变化? 负载增加,如果要保持性能不变,需要增加多少资源? 本系统的性能指标如何衡量?(吞吐量?响应时间?) 负载增加时,如何保持良好的性能?(垂直拓展:升级到更强大的机器。水平拓展:将负载分布到多个更小的机器,无共享体系结构) 弹性拓展:自动检测负载增加,自动添加更多计算资源 手动拓展:人工分析性能表现,手动添加更多计算资源 无状态服务水平拓展比有状态服务更容易。 超大规模的系统要针对应用定制,没有一套通用的框架,所以说这种架构师的岗位是无法替代的,有出路,可以一直搞,从通用的组件定制出一个超大规模的系统。 可维护性 运维简单、项目复杂度低、易于改变 第2章:数据模型与查询语言 每层通过提供一个简洁的数据模型来隐藏下层的复杂性。 数据模型 层次模型: 不好用,基本用下面三种 关系模型: 写时模式(写时强制) 劣势:对象-关系不匹配(阻抗失谐,需要一个转换层也就是ORM) 文档模型: 读时模式(读时处理) 图模型 读时模式(读时处理) 所有数据都有可能相互关联 一个模型可以用另一个模型来模拟,但是在不同场景下,有的模型过于笨重,所以不同的系统用于不同的目的。 还有其他的模型(全文索引等) 查询语句 命令式 告诉计算机以特定的顺序执行某些操作,指定如何实现 声明式 只需指定所需的数据模式,不需要指定如何实现,系统自动选择 MapReduce 编程模型 查询的逻辑用代码片段来表示,这些代码片段可以被处理框架重复地调用。 基于函数语言中的map(也称collect)和reduce(也称fold或inject)函数 第3章:存储引擎 日志:表示一个仅能追加的记录序列集合。 墓碑:表示这个记录被删除的标记 索引结构 哈希索引: 必须全放进内存(放到磁盘基本没用) 不能简单支持区间查找 存储段key-value对不需要有序 值可以是实际行(文档,顶点),也可以是对其他地方存储的行的引用(这个用的多,因为存在多个二级索引的时候就可以避免复制数据),存储具体行的文件叫堆文件, 聚集索引: 在索引文件中保存行数据 非聚集索引: 索引文件中只存储数据的引用 覆盖索引: 多列索引: 全文索引和模糊索引: 日志结构 SSTable(排序字符串表) key-value对有序...

September 21, 2022 · 1 min

Python的路径和版本管理

我现在的mac上已经安装了如下几个python /opt/homebrew/opt/python@3.10/bin/python3.10 /usr/bin/python3 /Library/Frameworks/Python.framework/Versions/2.7/bin/python 这些包从哪里安装的 homebrew的安装包是通过homebrew使用brew命令进行安装的,可以使用brew uninstall进行卸载,如果brew安装的其他项目有使用python,就无法直接卸载了。 /usr/bin/python3这个python是系统自带的,不推荐卸载,/usr/bin/python3应该是一个硬链接。 python2是为了使用npm安装不得已下载的。 pip install安装的包放在哪里? 对于mac自带的python3,系统做了一些工作使得这个的安装包路径在/Users/<user_name>/Library/Python/3.8/lib/python/site-packages下 参考博客https://frostming.com/2019/03-13/where-do-your-packages-go/ Python 是如何寻找包的 现在大家的电脑上很可能不只有一个 Python,还有更多的虚拟环境,导致安装包的时候,一不小心你就忘记注意安装包的路径了。首先我们来解决找包的问题,这个问题回答起来很简单,但很多人不知道这个原理。假如你的 Python 解释器的路径是 $path_prefix/bin/python,那么你启动 Python 交互环境或者用这个解释器运行脚本时,会默认寻找以下位置1: $path_prefix/lib(标准库路径) $path_prefix/lib/pythonX.Y/site-packages(三方库路径,X.Y 是对应 Python 的主次版本号,如 3.7, 2.6) 当前工作目录(pwd命令的返回结果) 这里如果你用的是 Linux 上的默认 Python,$path_prefix 就是 /usr,如果你是自己使用默认选项编译的,$path_prefix 就是 /usr/local。从上面第二条可以看到不同 Python 版本的三方库路径不同,如果你把 Python 从 3.6 升级到 3.7 那么之前装的三方库都没法用了。当然你可以整个文件夹都拷贝过去,大部分情况不会出问题。 几个有用的函数 sys.executable:当前使用的 Python 解释器路径 sys.path:当前包的搜索路径列表 sys.prefix:当前使用的 $path_prefix 为什么vscode的终端使用的python3是brew的而系统的终端用的默认的python3 我重新打开了一个系统的终端之后也变成使用brew自带的了,说明是环境变量设置的问题。 使用echo $PATH查看环境变量,得到结果 /Users/chuhuilong/.nvm/versions/node/v10.15.3/bin:/Library/Frameworks/Python.framework/Versions/2.7/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin 管理python 使用python遇到的最大问题就是python的版本管理了,虽然使用其他的语言也会有版本管理问题,但是python最大的难点在于,python2和python3不兼容,并且它们的安装方式还有多种,安装下来的位置也都不同。另外有些系统比如mac自带python3,种种原因使得python的版本管理地位非常重要,没有好的版本管理,就不清楚自己在运行什么版本,下载的包也会丢在不同的地方。 pyenv 根据这篇文章https://opensource.com/article/19/5/python-3-default-mac,博主在安装另一个软件时也遇到了和我一样的问题,python版本太多太混乱。很多人遇到了这些问题,于是有了各种解决方案,其中pyenv受到了Moshe Zadka的推荐。 pyenv使用很简单 安装brew **install** pyenv 下载指定pythonpyenv install 3.10.0...

September 17, 2022 · 1 min

pwndbg练手

pwndbg pwndbg是gdb的一个拓展,使用体验比gdb好很多。使用文档。 查看static变量存储在哪儿 编写一个测试程序staticMemberInClass.cpp。 class TestClass { public: static int static_member; }; int TestClass::static_member = 20; int main() { TestClass::static_member = 30; } 编译g++ -g staticMemberInClass.cpp -o staticTest.o 调试gdb ./staticTest.o 在main函数处打断点,b main 运行r 这个输出结果就人性化很多了 vmmap查看虚拟内存映射 可以看到是没有堆的,使用heap查看堆 进一步证实了此时确实还没有堆 p &TestClass::static_member查看静态成员的地址 结合汇编代码 运行到此处时,p $rip+0x2ed5查看将0x1e也就是30存在哪个地址了 算上dword正好是static_member的地址 x/wd 0x555555558010查看一下该地址的值 多方面都印证了static_member存储在这个地址 vmmap查看一下0x555555558010在属于哪个部分 很明显存储在数据段中。

May 31, 2022 · 1 min

热更新demo

运行时加载 动态链接库提供的API 函数声明 /* Open the shared object FILE and map it in; return a handle that can be passed to `dlsym' to get symbol values from it. */ extern void *dlopen (const char *__file, int __mode) __THROWNL; /* Unmap and close a shared object opened by `dlopen'. The handle cannot be used again after calling `dlclose'. */ extern int dlclose (void *__handle) __THROWNL __nonnull ((1)); /* Find the run-time address in the shared object HANDLE refers to of the symbol called NAME....

May 31, 2022 · 3 min

ELF文件格式

ELF文件格式 建议下载下面这张图片,再对照下方的注释查阅。 [1]ELF文件类 Untitled Database [2]字节序 Untitled Database [3]文件类型 Untitled Database [4]机器类型 Untitled Database [5]段的类型 Untitled Database [6]段的标志位 Untitled Database [7]段的链接信息(sh_link&sh_info) 如果该段的类型与链接有关,则意义如下,否则无意义 Untitled Database [8]符号类型 Untitled Database [9]符号绑定信息 Untitled Database [10]符号所在段 如果符号定义在本目标文件中,那么这个成员表示符号所在的段在段表中的下标。 否则,如下表 Untitled Database [11]常见类型值 Untitled Database [12]重定位入口的偏移 Untitled Database 参考文献:《程序员的自我修养》

May 12, 2022 · 1 min

如何方便地阅读Arduino或Esp8266的源代码

如何方便地阅读Arduino或Esp8266的源代码 Windows(Sourcetrail+ArduinoCLI) 需要用到的工具 Sourcetrail ArduinoCLI 根据官方手册,下载windows下的压缩包,解压后的文件夹种有一个arduino-cli.exe,执行文件。假设改执行文件的路径为D:\arduino-cli\arduino-cli.exe,用管理员权限打开cmd进入该目录。 Arduino 根据官方手册,先使用arduino-cli core update-index更新一下缓存。将Arduino的板子插入电脑的接口后,使用arduino-cli board list后,core会告知改板子使用的核心,比如我用的Arduino UNO R3,core是arduino:avr,那么需要下载该corearduino-cli core install arduino:avr,如果这个时候出现Access is denied错误,根据issues723,关闭一下杀毒软件在尝试一次(我使用的火绒导致静默阻止)。core安装成功之后可以使用arduino-cli core list查看一下所有已经安装的core。其他使用方法可以参考官方文档,重点是如何更好地阅读代码。假设我们要阅读的代码是MyFirstSketch.ino,那么根据官方手册可以执行arduino-cli compile -b esp8266:esp8266:nodemcu HttpOTA --only-compilation-database -v,–only-compilation-database会在build目录下生成comile_commands.json文件,-v会显示具体的信息,而build目录就是输出最后arduino-sketch文件所在的目录。 找到comile_commands.json文件后就可以直接用Sourcetrail打开,创建新项目时选择CDB,里面选择comile_commands.json文件(建议复制到源文件目录下,sourcetrail的项目文件也选择源文件目录),解析头文件选择从cdb中导入就行,这样解析之后虽然还会有一些error和fatal,但是基本上不影响源码阅读。 esp8266 方法和Arduino使用差不多,根据官方手册安装esp8266的库文件用这个命令 arduino-cli core update-index --additional-urls https://arduino.esp8266.com/stable/package_esp8266com_index.json 注意连接板子查看具体的board型号。 WSL2 加入需要在Windows上的WSL2里面使用ArduinoCLI,vscode使用compile_command.json来解析的话,会遇到下面一些问题。 WSL2目前不支持串口映射,解决办法时根据微软的手册安装软件进行手动映射。 在Linux环境中遇到avrdude: ser_open(): can’t open device “/dev/ttyACM0”: Permission denied问题,sudo chmod a+rw /dev/ttyACM0 arduino-cli core install esp8266:esp8266 arduino-cli compile -b esp8266:esp8266:nodemcu HttpOTA --only-compilation-database -v C:\Users\18454\AppData\Local\Temp\arduino-sketch-776950451AE70DA4FF60E70254F9E1B8

April 27, 2022 · 1 min