概述
软件的工程性表此刻质量与效率。单测是组成软件质量的第一道防地,而单测包围率是软件质量的重要指标之一。 编写容易测试的代码,可带来更佳的单测包围率,间接晋升开拓效率。
为什么措施员不大写单测呢? 主要有如下原因:
针对上述环境,利用“代码语义化”、“疏散独立逻辑”、“疏散实例状态”、“表达与执行疏散”、“参数工具”、“疏散纯函数”、“面向接口编程”的能力,用于编写更容易测试的代码。
能力
代码语义化
在工程中,经常多处看到雷同无语义的代码:
if (state.equals(5)) { // code .... }
这段代码有两个问题:(1) 无语义,易反复; (2) 容易引起 NPE。 state.equals(5) 是想表达什么业务语义呢? 在差异规模里,有差异的寄义。好比用于订单状态,可用于表达已付款。那么,代码里就应该明晰表达这一寄义,新建一个类 OrderStateUtil 及 isOrderPaid() ,把这段代码放进去;另外,假如 state = null,会引起 NPE,因此保险的写法是 Integer.valueOf(5).equals(state) 。 这段代码可写作:
public class OrderStateUtil { public static isOrderPaid() { return Integer.valueOf(State.ISPAID).equals(state); } }
这些,就可以对这段代码举办测试,而且多处安心引用。 像这样的代码,可称之“业务点”。 业务系统中布满着大量这样的细小的业务点。将业务点抽离出来,一则可以大量复用,二则可以任意组合, 就能制止系统重构时需要改多处的问题了。
将纯真的业务点从要领中疏散出来。
疏散独立逻辑
独立逻辑是不依赖于任何外部处事依赖的业务逻辑或通用逻辑,切合“沟通输入运行任意次老是获得沟通输出”的函数模子。独立逻辑容易编写单测,然而许多开拓者却习惯把大段的独立逻辑放在一个大的流程要领里导致单测难写。来看这段放在流程要领里的代码:
if(!OrderUtils.isNewOrderNo(param.getOrderNo())){ deliveryParam.setItemIds(param.getItemIds().stream().map(itemId->itemId.intValue()).collect(Collectors.toList())); }else { deliveryParam.setItemIds(param .getItemIds() .stream() .map( x -> { if (orderItems.stream().anyMatch(orderItem -> x.equals(orderItem.getTcOrderItemId()))) { return orderItems .stream() .filter(orderItem -> x.equals(orderItem.getTcOrderItemId())) .map(orderItem -> orderItem.getId()) .collect(Collectors.toList()).get(0); } else { return x.intValue(); } } ).collect(Collectors.toList()) ); }
这段代码本质上就是获取itemIds并配置参数工具,由于嵌入到要领中,导致难以单测,且增大地址要领的长度。另外,不须腹地利用stream的双重轮回,导致代码难以领略和维护。假如这段逻辑很是重要,将一段未测的逻辑放在逐日挪用百万次的接口里,那的确是存荣幸心理,犯兵家之忌。该当抽离出来,建设成一个纯函数:
private List<Integer> getItemIds(DeliveryParamV2 param, List<OrderItem> orderItems) { if(!OrderUtils.isNewOrderNo(param.getOrderNo())){ return StreamUtil.map(param.getItemIds(), Long::intValue); } Map<Long, Integer> itemIdMap = orderItems.stream().collect( Collectors.toMap(OrderItem::getTcOrderItemId, OrderItem::getId)); return StreamUtil.map(param.getItemIds(), itemId -> itemIdMap.getOrDefault(itemId, itemId.intValue())); } public class StreamUtil { public static <T,R> List<R> map(List<T> dataList, Function<T,R> getData) { if (dataList == null || dataList.isEmpty()) { return new ArrayList(); } return dataList.stream().map(getData).collect(Collectors.toList()); } }