L`Bat的博客
为者常成 行者常至
creed
- 控制复杂性是软件开发的根本
testable_code
概念
集成测试对用户的交互行为感兴趣,而单元测试往往仅专注于一小段代码
软件IC是人们在讨论可复用性和基于组件的开发时最喜欢使用的比喻。意思是软件组件应该就像集成电路一样进行组合,这只有在你使用的组件已知是可靠地时候才能行之有效。
芯片在设计时就考虑了测试——不只是在工厂,在安装时,而且也是在部署现场进行测试。更加复杂的芯片和系统可能还拥有完整的Built-In-SelfTest(BIST)特性,用于在内部运行某种基础级的诊断;或是拥有Test Access Mechanism(TAM),用以提供一种测试装备,允许外部环境提供激励,并收集来自芯片的响应。
untestable的代码
- 隐藏的输入
- 依赖过多,构建麻烦
- 耦合度过高
- 非单一职责
- 显式的依赖DB NETWORK 未测试的类等(应该依赖接口或者mock)
验收标准
- 覆盖率高(路径被遍历)
- 圈复杂度低
- 每个输入有唯一的输出
- 过去的系统状态和变量可见,或在运行中可查询(例如:事务日志)
- 软件的可测试性特征主要表现是设立观察点、控制点、观察装置、驱动装置、隔离装置
pricinple
- 设计之初就考虑了
测试模式
- 承认单元测试不是万能的,只保证部分正确
- 尽量少的依赖
First rule of writing testable code to me is having a good dependency management within the code base, or at least having the least possible dependencies in your object/module relations
执行路径过多(每个执行路径是不同的代码,都该有个测试与之对应)
应该由单个方法来决定if的条件
嵌套的panduan
== null
> 2可控性指系统的状态可受外部控制改变,而不是由内部模块自发的完成
测试环境不可以等待每天晚上1点这个时刻
- 可观测性
再次,没有必要的描述如何判断哪些文件/数据被GC掉了。无法观测到执行结果集带来的后果是无法精确的预期测试结果。
- 参数的热设定
- 系统使用信息统计
NOT testable
- 包含不确定的因素1234567891011121314151617public static string GetTimeOfDay(){DateTime time = DateTime.Now;if (time.Hour >= 0 && time.Hour < 6){return "Night";}if (time.Hour >= 6 && time.Hour < 12){return "Morning";}if (time.Hour >= 12 && time.Hour < 18){return "Afternoon";}return "Evening";}
- 依赖了系统时间
- 隐藏了输入(依赖)
- 相同测试不同输出
测什么
CORRECT
实现
- 完全的TDD
- 实现-> 测试 -> 重构以更testable -> 更多测试 -> 重构测试
todo
- 监视圈复杂度
java-concurrent
cache
controller-handle
![处理流程图]
流程
- 处理
OPTIONS
请求 allowHeader可配置 - 检查Method是否被支持
- 检查session
- 处理Cache-Controller 可配置
- 处理Vary 可配置
- handleRequestInternal
TODO:
- Session 何时多个线程同步一个session
设计模式:适配器模式
定义
适配器模式(Adapter Pattern):将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)
形象
- 手机充电口
参与角色
- Adaptee
- AbstractAdapter 固定的一端确定
- ConcreteAdapter
- Target (可以使调用方,也可以是被调用方)
案例
- springmvc中对handler的处理123456789101112131415161718192021222324252627282930313233343536373839404142434445//AbstractAdapterpublic interface HandlerAdapter {boolean supports(Object handler);ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;}//Adaptee Apublic interface Controller {ModelAndView handleRequest(HttpServletRequest, HttpServletResponse);}//ConcreteAdapter Apublic class HttpRequestHandlerAdapter implements HandlerAdapter {public boolean supports(Object handler) {return (handler instanceof HttpRequestHandler);}public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {((HttpRequestHandler) handler).handleRequest(request, response);return null;}}//Adaptee Binterface Servlet {public void service(ServletRequest req, ServletResponse res)}//ConcreteAdapter Bpublic class SimpleServletHandlerAdapter implements HandlerAdapter {public boolean supports(Object handler) {return (handler instanceof Servlet);}public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {((Servlet) handler).service(request, response);return null;}}
java-exception
使用cause创建
递归getCause
找产生错误的根源
spring-flashmap
spring mvc处理http请求的过程
介绍servlet
实际上是遵循了servlet规范
- doPost / doGet 调用
DispatcherServlet.doService
- request可以存取attribute, 存储原有attrs
- 设置常用attrs
- context
- localeResolver 修改点
- themeResolver 修改点
- 处理并设置
FlashMap
(FlashMap是不同请求间共享数据的方式)
处理multipart
- 使用multipartResovler处理
- 如果错误写入错误到attrs(attrs是MultiValueMap)
在
List<HandlerMapping>
中找第一个HandlerExecutionChain
修改点- 如果是Get请求, 处理302
- ETag
- lastModified
- 设置302
- 写回
Last-Modified
- 请求
SimpleUrlHandlerMapping
(求改点)得到HandlerExcutionChain
- 如果是handler是String,那么去context里拿到Bean作为handler
- 在Mapping中获得匹配的(
Interceptor.matches
)来加入Chain
- 分配请求到
HandlerExecutionChain
- 调用
HandlerInterceptor.preHandle
, 一次调用,有false结束 - 调用
HandlerInterceptor.handle
, 获得MoSimpleControllerHandlerAdapterdelAndView; handle内部 - 调用
HandlerInterceptor.postHandle
常用实现
SimpleControllerHandlerAdapter
每个Handler的实现自己提供Adapter, 因为handler是个object
- 调用
- 如果发生
Exception | Throwable
,调用preHandle
已经返回true的Interceptor.triggerAfterCompletion
修改点 - 清理multipart 修改点