如何正确的使用Mock[1] 软件测试
首先我不是反Mock者,但确实对应用Mock持对照慎重的态度,由于Mock是非常难于正确应用的, mock最稀有的问题在于如果!如果!如果!
有这样一个功能,当有义务的时候,人民需要买需要买医疗保险,住房公积金和养老保险,如果失业了他只需要买养老保险:
public void requreInsurance(Insurances insurances) 【
if (people。getJob() == null) 【
insurances。add(new RetirementInsurance());
】 else 【
insurances。add(new HealthInsurance());
insurances。add(new RetirementInsurance());
insurances。add(new HouseFund());
insurances。add(new UnemploymentInsurance());
】
】
相应的Mock测试有两种状态需要掩饰:
× mock people对象, 如果getJob方法返回null,验证insurances中只有包含养老保险
× mock people对象, 如果getJob方法返回Not null,验证insurances中包含四金
在这里的Mock测试进行了如果,它的coorelation people对象在有义务的时候返回非Null的Job对象,而在没有义务的时候返回Null,类似的代码在任何一个项目中都可以找得到踪迹。
问题在于这样的如果可以被悄无声息的破坏掉,如果有人重构了People对象, 在没有义务时返回一个new NullJob()对象(Null Object Pattern), 这样重构后,失业的人也不得不买四金了,然而我们之前编写的mock测试会100%的通过
如何解决这样的问题呢?
功能测试是一个解决思路,由于在Mock测试中,我们始终的在层与层之间做出如果,一定需要一个端到端的测试来验证我们的如果是否正确。功能测试解决了部分的问题, 回想上面的问题,你发现至少需要编写两个功能测试才能百分之百的发现刚才重构引入的bug, 如果只编写了happen path的功能测试(有People义务的功能测试),那你只有祈祷QA能帮你及时的找到问题了。不幸的是,由于功能测试的代价对照大,所以大多数的人都只会编写有限的功能测试,往往这些测试仅仅用于掩饰Happy path。 对于如此简单的问题功能测试尚且不能解决问题,更遑论我们“大型企业级超复杂”的项目呢。
另一个方法就是增添如果,回想一下我们的实现代码:
if (people。getJob() == null) 【
。。。。
】 else 【
。。。。。
】
getJob的返回值是我们需要进行两次如果的根源,如果没有返回会怎样?