SpringBoot 测试实践 - 2:单元测试与集成测试

上一节:SpringBoot 测试实践 - 1:常用的工具 下一节:SpringBoot 测试实践 - 3:@MockBean、@SpyBean 、提升测试运行速度、Testcontainer 单元测试 vs. 集成测试 只编写单测,无法测试方法之间的集成情况,而且某些需求可能会修改多个方法,这可能会影响方法对应的单测,涉及到大量的相关单测的修改,这样的维护成本很高 可以把重心放在完善集成测试上,专注从外部判断程序是否符合预期。对于一些非常重要的方法,增加单元测试可以减轻集成测试排查错误的难度 先导知识可以参考上一节:SpringBoot 测试实践 - 1:常用的工具 SpringBootTest 和 MockMvc 进行集成测试 从 Spring Boot 2.1 开始 @ExtendWith({SpringExtension.class}) 作为元注解包含在 Spring Boot 测试注解中,例如 @DataJpaTest、@WebMvcTest 和 @SpringBootTest,所以我们不用重复添加 @ExtendWith({SpringExtension.class}) 注解 HelloWorld 测试 使用 SpringBoot 一个简单的 HelloWorld 案例,通过 @SpringBootTest 可以在测试环境中加载整个 Spring 应用程序上下文,@SpringBootTest 注解会扫描应用程序的主配置类,并加载所有的 Bean(包括依赖的 Bean)到测试上下文中。这样,测试中就可以使用完整的 Spring 功能,包括依赖注入、AOP、事务管理等 使用 @AutoConfigureMockMvc 自动配置 MockMvc,通过 MockMvc 可以模拟 HTTP 请求,并对响应的结果进行断言和验证 import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultMatchers; @AutoConfigureMockMvc @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class MySpringBootTest { @Autowired private MockMvc mockMvc; // 注入 MockMvc @Test public void testHelloWorld() throws Exception { // 发送 GET 请求 mockMvc.perform(MockMvcRequestBuilders.get("/hello") // 设置请求头 .accept(MediaType.APPLICATION_JSON)) // 验证响应状态码 .andExpect(MockMvcResultMatchers.status().isOk()) // 验证响应内容 .andExpect(MockMvcResultMatchers.content().string("Hello, World!")); } } 涉及数据层的测试:H2 部分操作涉及到数据库,一般都会引入数据层的依赖,在对应的 HTTP 请求后,对响应体和数据库数据进行断言和验证,就像下面这样: ...

August 22, 2023

SpringBoot 测试实践 - 1:常用的工具

下一节:SpringBoot 测试实践 - 2:单元测试与集成测试 我自己接触到的一些商业或是开源的基于 SpringBoot 项目,它们大部分是没有测试代码的,test 文件夹只有脚手架初始化生成的那个测试类,跟不同的开发聊到这个话题,发现他们中的大部分没有写测试的习惯,或者是觉得写测试代码麻烦,主要还是依赖测试工程师做黑盒的测试。只做黑盒测试的话有一定的的局限性,一些边界的条件可能就覆盖不到,而且相对来说人也比较容易出错、遗漏。而测试代码能解决其中很大一部分的问题,利用好单元测试和集成测试在某些情况下相对于直接通过 UI 进行测试是要更方便、节省时间的,所以想通过几篇博客来分享一下自己的测试实践 为什么要写测试(优点) 覆盖更多的边界条件,且随时都可以运行测试代码(一劳永逸) 缩小测试范围:测试某个方法只需要运行对应的测试代码,而不需要运行整个项目通过请求接口进行测试 对重构更友好,可以随时重构有集成测试的代码,不用担心打破原有的代码 其他人也可以通过测试快速地理清楚对应被测代码的主线逻辑(类似文档的作用,特别是复杂代码,通过测试能快速理解上手) 写测试的过程,给自己一个新的视角去审视代码结构的设计,有助于改善代码设计 当然代码方式的测试也并非完美无缺:测试代码增加编写和维护的成本,同时一些外部依赖也需要通过 Mock 的方式实现,这些都提高了整个测试编写的门槛。也倒逼我们思考更好地组织代码,减少依赖 另一个方面:测试对于重构也是至关重要的,随着对业务的理解越来越深刻,可以重构代码,抽象出了一些共性的逻辑,优化代码结构,但是如果没有相关测试,面对着旧代码就只能望而却步了 测试工具:JUnit 5, AssertJ,Mockito spring-boot-starter-test 自带常用的测试工具:JUnit5、Assertj、Mockito,可以直接使用 JUnit5 Junit 5 包含: JUnit Platform:Test Engine Jupiter:编程模型和拓展模型 Vintage:兼容老版本 JUnit 4 和 5 使用的包有所不同 // JUnit 4 import org.junit.Test; import static org.junit.Assert.assertEquals; // JUnit 5 import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; 如果不考虑兼容 JUnit 4 的测试,我们可以直接在依赖中直接排除 JUnit 4 的依赖,这样也可以避免在使用的时候错误地引入 JUnit 4 的包 ...

August 21, 2023

快速重拾 Tmux

Tmux 是一个 Linux (Mac OS也支持)下的终端复用器,相较于 Screen 更为强大,但快捷键和操作逻辑也更复杂,一段时间不用,就很容易忘记相关的命令和快捷键。本文旨在通过一个简单的场景,快速重拾 Tmux Tmux 通常用来保持会话(session),如果我们通过 ssh 连接服务器处理打包等的耗时操作,那么网络波动可能会导致连接断开,使得操作失败,使用 Tmux 会话会被保持,任务依然会继续,我们可以随时恢复会话 Tmux 另一个常用的功能是分屏,快速地创建 Window 和 Pane,方便地在不同的任务间穿梭 修改配置 vim ~/.tmux.conf # 将默认修饰键(prefix) ctrl + b 修改:ctrl + a set -g prefix C-a unbind C-b bind C-a send-prefix # 激活鼠标模式 set-option -g -q mouse on # 修改分屏快捷键 # 左右分屏 bind h split-window -h # 上下分屏 bind v split-window -v # 可以取消默认的分屏快捷键映射 # unbind '"' # unbind % # 将 tmux 的复制模式键绑定设置为 vi 模式 setw -g mode-keys vi # windows 和 panes 的序号从 1 开始 set -g base-index 1 setw -g pane-base-index 1 重新加载 Tmux 配置文件 ...

April 13, 2023

32 位计算机时间戳溢出的思考 —— 整数的二进制表示

Year 2038 problem 在 CS50 第 01 讲:C语言 中,提到了一个很有趣的问题:Year 2038 problem,这个问题指的是:一些使用 32 位来存储时间戳的计算机,在 2038 年,可能会出现整数溢出的问题,导致计算机的时间倒退回 1901 年 时间戳 指得是:UTC 1970 年 1 月 1 日 0 时 0 分 0 秒到现在经历的秒数,用时间戳就可以表示当前的时间 为什么会出现这个问题呢?因为时间总是在流逝,所以每时每刻时间戳都在增加,但是 32 位的存储空间是有限的,总有一天会超出所能存放的最大值,而反直觉的是在超过了最大值后并不是归零(时间戳回到 1970),而是倒退到了更前的 1901 年,对应下面的表格我们就可以更直观地看到几个时间戳对应的具体时间 时间戳 对应的 UTC 时间 0 1970-01-01 00:00:00 2147483647 (32 位 int 最大整数值:2^31 - 1) 2038-01-19 03:14:07 -2147483648 (32 位 int 最小整数值:-2^31) 1901-12-13 20:45:52 可以看到当存储超过位数能容纳的最大值时,该值会从一个非常大的正数突然变为一个非常小的负数,所以导致了日期回到了 1901 年 原码、反码、补码 计算机底层是通过二进制的方式存储整数,两者转换可以参考文章:二进制和十进制之间的互相转换,除了整数的大小,还需要存储的是整数的正负,一般首位(最高位)用于存储正负,0 代表该整数为正数,1 代表该数为负数,将一个整数对应的二进制数转化为计算机存储的二进制数,这个变换就是《数字逻辑电路》里面经常提到的原码、反码、补码转化。注意:正数和 0 的原码、反码、补码相同,负数则需要转换 我们回顾一下,以 4 位二进制表示的整数举例:0 的原反补码都是 0000,1 的原反补码都是 0001,而 -1 该如何表示呢? ...

November 9, 2022

Git 中的回退操作:reset 和 revert

Git 中回退有 reset 和 revert,这两个的区别就是是否保留更改记录 假设当前的提交情况是:A <- B <- C <- D <- HEAD,如下图: 当前是 D,希望回退到 A,那我们可以使用 reset 命令,reset 后再看 git log 就会发现:B <- C <- D 宛如没有出现过,这适用于想完全舍弃 A 之后的修改 但是如果我们想保留 B <- C <- D 的修改记录,可能这三个 commit 的功能只是暂时用不到,以后可能还用到,或者可能当前分支是一个公共分支,B <- C <- D 可能已经被同步到了其他小伙伴电脑上,为了尽量避免代码冲突。这些情况就需要使用 revert 命令,这样会重新生成新的 commit,其中包含回退的记录(假设 D 这个 commit 是添加了一些代码,那么 revert D 的 commit 就是删除这些代码) reset 使用 git reset A ,reset 会修改 head 的指向,这样可以回滚到 A,默认使用的参数是 --mixed,这个参数决定了 reset 时 Git 该如何处理工作区和暂存区 ...

July 8, 2022

安卓导航抽屉 Navigation Drawer 实现沉浸通知栏

在使用 Navigation Drawer Activity 模版的时候,遇到了通知栏无法完全沉浸的问题,尝试搜索一些现有的解决方法,但是或多或少都会存在一些问题,通过反复尝试找到找到了一种比较靠谱的思路 环境 测试模拟器:Pixel 3A compileSdk:32 minSdk:28 targetSdk:32 创建工程 默认效果展示: 修改步骤 设置状态栏变为透明:修改主题配置 <item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item> 修改为: <item name="android:statusBarColor">@android:color/transparent</item> 修改后完整文件: <resources> <!-- Base application theme. --> <style name="Theme.MyApplication" parent="Theme.MaterialComponents.DayNight.DarkActionBar"> <!-- Primary brand color. --> <item name="colorPrimary">@color/purple_500</item> <item name="colorPrimaryVariant">@color/purple_700</item> <item name="colorOnPrimary">@color/white</item> <!-- Secondary brand color. --> <item name="colorSecondary">@color/teal_200</item> <item name="colorSecondaryVariant">@color/teal_700</item> <item name="colorOnSecondary">@color/black</item> <!-- Status bar color. --> + <item name="android:statusBarColor">@android:color/transparent</item> <!-- Customize your theme here. --> </style> <style name="Theme.MyApplication.NoActionBar"> <item name="windowActionBar">false</item> <item name="windowNoTitle">true</item> </style> <style name="Theme.MyApplication.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" /> <style name="Theme.MyApplication.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" /> </resources> 修改后的效果: ...

May 10, 2022

使用 Postman 的 Environments 和 Tests 简化在不同环境中的切换步骤

调试 API 的时候,我们需要经常需要在本地、开发、生产来回切换,还需要面临 Token 失效等的问题,让人头大,看到一些教程有介绍用 Postman 来简化流程,但是实践起来还是遇到一些问题,所以就有了这篇细致地介绍使用 Postman 的 Environments 和 Tests 来简化在不同环境中切换的步骤,无感知地调试 API 的博客 手动更新 Token 在 Environments 面板中 new 一个新的 Environment (环境),用于存储当前环境的:Token、地址、用户名、密码,需要先填上地址、用户名、密码的 CURRENT VALUE 在 Collections 中添加一个新的 Collection(集合),名字为 Demo,点击右键选择 Add Request 添加一个获取 Token 的 Request。注意右上角的 Environment 需要选择刚才定义的,这样才可以通过 {{}} 获取到 Environment 中变量的值。这里的 base URL、账号、密码都可以根据实际请求的情况进行设置 编写这个 Request 的 Test(Test会在请求执行后自动运行),编写 Test 目的是为了在请求后自动更新当前 Environment 的 Token,写完就点击 Send 发送请求。点击右上角的眼睛,可以快速查看当前 Environment 变量 // 判断相应的状态码是否为 200 pm.test("Status code is 200", function () { console.log((pm.response)) pm.response.to.have.status(200); }); // 更新当前 Environment 的 Token console.log(pm.response.json()) var token = pm.response.json().token pm.environment.set("token", token); 使用 Request 调用获取 Token 的 Request,更新全局 Token ...

March 4, 2022

我的二本学生 阅读笔记

第一次知道黄灯老师是在随机波动的播客:【随机波动025】一本二本的尽头是否都是就业零件? 后面又在软工教学群里看到了分享:专访《我的二本学生》作者黄灯:看见中国普通年轻人的命运 随后也看到了十三幺:许知远对话黄灯 我和我的二本学生 以及黄灯老师的演讲:黄灯:二本学生的困境,也是当下所有年轻人的危机 近期翻阅了黄灯老师所写的这本札记,对于所提到学生有了更具象的了解,书中一些片段与生活认知有高度的重叠,其中就包括:苦难对于学生不同的影响、原生家庭对于孩子成长的影响、大的时代背景下的个体的选择和命运、多子女家庭和独生子女家庭学生性格的差异 看这本书的时候,我总会回想起大学时期担任软件工程助教的那些事情。通过助教这个工作,有幸以另一种角度窥见自己所在的学校、自己熟悉的课堂,见证同学们学习的状态。在结束了一个学期的助教工作后,我越发了解同学们的所面临的境况,同时也更深刻地感受到了教师的无奈,以及他们所面临的困境。对于我来说有时这种绝望是打在身上的,能够触及的改变太少了 正如黄灯老师所说的: 我希望我的学生毕业之后都能在社会上立足,不要过着很艰难的生活 我也希望他们更有冲劲,能够去追求梦想,有更多的勇气,但我知道其实很多爸爸妈妈,他们希望自己的孩子读完大学之后有一份稳定的工作,让父母放心,在城里面立足 我也看到有不少学生,在坚持自己的理想和底线的时候,在现实中会碰的头破血流 我们作为过来人其实在他准备那样去做的时候就能够预料到他的后果,但是当时可能也不忍心去把他的那种激情破灭,但是事实上你过了好多年,再回过头去看其实孩子还是付出很大的代价 这个社会的反,抗不能完全由年轻人冲到前面,我觉得这个社会的改革应该首先从反省自己开始,尤其是那些获得利益的人 一个农村来的孩子,父母通过打工,在外面卖苦力来供养他读书,说句不好听的,你指望他来改变这个社会,我觉得太残酷了 互相看见是特别重要的,互相看见才会达成和解,这社会才会产生一种韧性的力量,而不是动不动就撕裂 序言 看见他们 中国二本院校的学生,从某种程度而言,折射了中国最多数普通年轻人的状况,他们的命运,勾画出了中国年轻群体最为常见的成长路径 写作的直接动因:课上的关于风的现场写作所引出的故事,让作者意识到了自己对于广东经济发展刻板印象 一 在龙洞 龙洞的变化折射了城市变迁史 不同的学生毕业后都租住在龙洞,伟福将住所收拾的妥帖,让人舒坦,在结束一天的工作后,能拥有让自己享受的空间 冉辛追将龙洞作为人生过渡期的暂居之处,受到爷爷的影响,对文学骨子里地热爱,最后却选择了人力资源专业,他的选择让爷爷迷茫和失望,这种遗憾也成为了他人生选择的隐秘动力,父母支持考研,提供生活费,通过三年的努力,最终成为复旦的一员。与之相似的还有姚大顺,他们都没有办法按照生活预设好的轨道前行,所以最终选择了考研,但家庭和成长环境不同,导致了大顺无法接受家人资助,全心考研。经过折腾最后回到了龙洞,他是家中的长子,母亲希望他可以稳定下来 除了身份已变,他的生活,和学生时代没有太大的不同,他依旧拥有龙洞,拥有学校的操场,拥有活色生香的饭堂,当然,也拥有大学时代低廉的生活成本,甚至还可以非常方便地联系想见的老师。这种便捷也许会让他忘记现实的残酷,淡化母亲给予他的忧伤,让他偶然沉湎咋学生时代的幻梦中 二 公共课 公共课所教授的《经济应用文写作》与博士期间所学习的写作之间的鸿沟是面临的挑战 对于人文学科而言,多媒体对于课堂的干扰和伤害,先让没有引起足够的重视,信息的泛滥及花里胡哨的内容,让老师无形中倍感压迫,也让学生在深度思考和理解上,缺乏锻炼的机会和耐心 邓桦真 《风》 写自己家境的贫寒,为贷款烦透心 朱洁韵 《父爱》 个性要强,来到大学后,幡然醒悟懂得了父亲的爱 面临的一个问题:无法触及一个真实群体的问题,企图借助考试,调动他们与己有关的生活经验,以此了解他们对于社会、自身的认知 让学生困惑的事情: 电子产品对生活的渗透 负载在家庭之上的生存挣扎 城市孩子:批判应式教育,深恶痛绝,刘奕晓比喻为“一场赌博”,方雪怡:高考作为划分线,中国学生的青春时代被简单粗暴地划分成两部分 农村孩子:充满闯过高考的庆幸惴惴不安 正因为经受了压力过大的考试阶段,课堂上学生中规中矩、老成持重,他们的平和中正与我们大学时代的张扬放肆,鲜明对比。他们收缩了属于青春年代的触角和锋芒,逼到绝境,唯一能够下手的对象只有自己 从记事起,无形的、细密的重荷就负载在他们身上,早已将他们裁剪得规规整整,难以在生活中泄露狡黠的契机 教育像一场慢性炎症,中小学时代服下的猛药、抗生素、激素,到了大学时代,终于结下了漠然、无所谓、不思考、不主动的恶果 三 班主任 因为班主任的身份,目睹了一个群体从学生时代,完全步入真实的社会,并和这个社会产生真实的关联 这些二本学生有的是在毕业后短暂挣扎,但最后又是为了解决生存 梦想,每个人都应该拥有,但不是每个人都能实现 大学毕业后,我的首要任务是要解决我和家人的生活问题 四任班长,其中能几个之所以能在社会立足,并过上让长辈放心、安心的稳定生活,要不就是早早认清现实的规划顺着社会去经营生活,要么就是是经过现实的碰撞,终于认清进入体制内工作的优势,选择毕业后回炉考公务员。志勇综合条件优秀,但是毕业后九年经历证明了,现实已经没有多少空间和可能 夹缝中的光芒: 钟梦兰:得益于中国高速的城市化进程,父亲从事建筑行业,在市里购地建房,在小城市生活 潘海燕:父母进城打工,保证了三姊妹的教育费用,没有重蹈村里贫困家庭长女的遭遇,早早辍学嫁人 广东发达经济条件和成熟的市场意识,导致家庭开过工厂或小作坊和内地农村家庭依赖农业的鲜明对比,造成职业观念的不同:倾向于从事商业活动 062111毕业生去向: 班上的女生很多在毕业后经过折腾,通过考公务员,进入机关事业单位,获得安稳工作,其二是银行、保险等金融机构,其三,国营、民营及各类私营企业,最后是:创业 梅怡的就业观中,没有动过寻找稳定工作的心思,和父母的鼓励、大城市出身、长大后的见识、较好的家庭经济条件分不开 062111学生之所以能在教育彻底市场化的境况下,获得良好的发展机会,显示了这一代普通青年,曾经拥有的丰富资源和时代机遇 分化已经开始: 一部分实现了财务自由,另一部分居无定所、收入有限,两者分野的关键要素是是否买房 ...

January 25, 2022

《马文 柯林斯的教育之道》阅读笔记

《马文·柯林斯的教育之道》 是 哈佛幸福课(积极心理学) 中强列推荐的一本书 这本书主写的是 马文·柯林斯 的成长经历已经和教育理念,仅看介绍,会误认为这本书只是在说鼓励式的教学理念,看完发现还有写塑造了她性格的人生经历,这部分更具有启发性。提及的很多点引起共鸣,能看到个人成长经历对于她教育方式的影响,最终形成的教育理念又改变了很多人的命运 马文儿时生活在亚拉巴马州蒙罗韦尔小镇,在这里远离了许多犯罪行为,人文、自然让她度过了无忧无虑的快乐童年。她目睹了因为种族的缘故父亲遭受到的不公待遇,但父亲从不墨守成规、安于旧俗 ,拥有强大的价值观和坚定信仰,这使得马文有强烈的安全感并且坚定自信 小时候通过模仿祖母诵读,马文学会了通过音节拼读单词,祖母读那些书籍诗歌启蒙了马文 小学时马文因写错2被老师用尺子打手,这影响了马文的教学理念:应该对孩子采取积极的策略,不应该指责和嘲笑,应该建立信心 ,孩子是敏感,自尊心是脆弱的 因为黑人身份在上学和就业时处处受到限制,致使她在培门罗县训机构教书,这段经历使马文掌握了教学方法,还让她懂得了优秀的教师更应该懂了解学生 在去芝加哥拜访祖母表亲安妮时,遇见了她的丈夫柯拉鲁斯,丈夫始终都很支持马文做的事 “能够对别人的孩子表现出极大耐心的男士一定会事一个好父亲和好丈夫” 在辞去医疗秘书工作后,马文到南卡尔洪小学二年级教书。传统教学通过图片教授阅读,这降低教材和课程难度,学生的反馈使得马文摒弃了这种教学方式,转而选择一些优秀的故事,教授孩子们正确的价值观和生活经验,这相较于传统课本更能激发阅读兴趣 办公室政治让马文失去了继续留在公立学校的动力,最终马文开始和一群对公立学校不满的女性邻居一起在 丹尼尔·黑尔·威廉姆斯大学 里建立了私立小学,在这所马文自己的小学里,她充分践行了她的教育理念,后来马搬到了自己家二楼并将学校改名为 西区预备学校,继续教书育人 马文给《芝加哥太阳时报》的专栏作家 扎伊·史密斯 写信,并接受了采访,之后收到关注和捐助,她到公立学校演讲,获得500美元,她也以此激励孩子努力学习 之后有了更多像 莉莲·沃恩、艾拉·麦考伊 这样的对待孩子温柔有耐心且乐于接受马文的教学方法的老师加入了马文的学校 《60分钟》栏目为学校打开资金来源,学校换了新的校址,有了更多的学生 面对各种正面和负面的报道,各种各样的批评,刚开始马文拒绝回应,朋友建议马文回应,但是这使得马文筋疲力竭 那些讥笑讽刺和含沙射影的批评永远不可能减少她真正的成就:那些孩子接受教育,受到鼓励,变得自信果敢,最后在这个世界上闯出了属于自己得路。这才是马文的宝贵遗产 马文教学的载体是基础读本中的每个故事,还引入了补充材料,培养学生发散性思维,用概括的方式来启发他们,让学生看见知识的流动 -> 用故事撑起孩子们广阔的知识面 -> 孩子们可把这些知识用于课堂、生活,从而形成正反馈不断激励孩子们自发学习。不局限于文学,她也会讲述歌剧及其背后的故事,她相信:要想让年轻人受到良好的教育,需要让他们接触所有的文化形式。她还在课堂上提出开放式的问题,激发学生批判性思维,提出省略事实的不完整问题,教会他们评估问题,意识到信息不充分 马文则坚信:“真正的解决途径就是教育,我们必须教会孩子自尊自立,我们必须教导他们,读书、培养技能和自立是非常重要的” “马文作为老师的最高目标就是赋予学生为自己学习的意愿” 教育的重中之重就是让孩子阅读,需要艰难且乏味的学习,没有任何捷径可走 危害当代教育一个弊端是由于过度强调“进步注意”的教学方法造成的。学校为了努力遵从 约翰·杜威 以学生为中学而非以课程为中心的教学理念,过多地牺牲了教学内容,过度关注如何教而不是教什么 在我们的学校里,没有奇迹,更没有魔法,否则教书对我而言就不会那么劳神费力了,学习对于这些孩子而言也不会那么艰辛困难了。正是由于所有的这些付出和艰难,孩子们才会细细品味每一次成功,并甘之如饴。并且一但他们开始成功了,便会想要更多,甚至不愿回头 马文擅长用鼓励或批评引导学生: “你们会学习所有的发音规律,这样的单词将不再是什么难懂的谜,多么富有或者多么漂亮。你可以和任何人对话,无论对方多么聪明,多么富有或者多么漂亮。你们都是聪明伶俐的孩子,没有什么事你们做不到的” “总有一天,在无数次的赞扬和拥抱之后,他的抵触情绪会自动消解。孩子们最终想要的是,一个真实的自己可以被接受,感受到自己是有价值的。一但他们感觉到自价值,就会痴迷于学习,而且永远都会求知若渴” 人和事分开,你的行为愚蠢 不等于 人愚蠢,这样学生才能接受意见和批评,放弃错误行为,而不是去尊严或自我价值 关注每一个孩子,这可能与她的经历有关,对于被孤立的感觉更能感同身受,她也提倡互助小组,不断督促彼此,为彼此取得的小成绩而感到快乐 课间看见独自的孩子会重新组织游戏玩伴,让每个孩子都感觉到被集体接受,不被排斥 每个孩子都需要感觉到被爱和被需要。每个孩子都需要归属感。大多数孩子依旧因为在之前的学校里被羞辱和被排挤而痛苦不堪 她不是被动地等着学生向她寻求帮助,而是常常就让自己在学生身边,通常困惑的孩子会呆在座位上,忘记了解决问题这件事,直到最后完全跟不上,彻底放弃 当你们想要伤害另一个人的时候,又怎么能够抱怨这个社会有种族偏见呢,所以你们学会互相帮助和相互爱护之前,不要谈论别人都对你们做了什么 她认为也应该把 ”不好的事物“ 也展现在孩子面前,这也是我们传统教育中比较缺失的东西,导致一部分人不知道该怎么面对现实生活中的苦难 ...

January 5, 2022

简单的 Shell 脚本入门教程

Shell脚本 运作方式与解释型语言相当,如果有语言基础,学起 Shell 脚本就非常容易,但是 Shell 与常见的语言不同,一些常见的函数在 Shell 中需要组合一些命令得以实现 工具推荐 Shell 似乎没有定制的 IDE,这里推荐 VS Code 搭配对应的插件: shellman 智能提示和自动补全,在插件页面有介绍常用代码片段的触发关键词,作者在 Shellman reborn 中写到了 Shellman 诞生的故事,挺有趣的 shellcheck 语法静态检查工具,插件安装后需要本地安装 shellcheck,参考 shellcheck Installing,Mac OS 可以使用 brew install shellcheck,这样在写 Shell 的时候,语法有误的地方就会以波浪线的方式提示 shell-format 代码整理,Win 快捷键:Alt + Shift + F,Mac OS 快捷键:option + shift + F Code Runner 脚本运行,右键 Run Code,Win 快捷键:Ctrl + Alt + N,Mac OS 快捷键:control + option + N 运行 shell 脚本 新建脚本:test.sh #!/usr/bin/env bash # 使用echo 打印字符串或者变量 echo 'hello world' 可以用 Code Runner 运行,就会输出:hello world ...

January 5, 2022