上一章之中,我们从测试的角度出发,说明了如何写好一个测试,这一章中,我们将要从另一方面,也就是被测试的代码角度出发,讲解一个什么样的代码才是适合被测试的代码。

对于一个代码来说,其必然伴随着时间的增大,带来更多的需求,从而导致复杂度加大。而在复杂度增大之后,如果不做好合理的拆分,那么会导致越来越不好测试。无法对单个模块进行测试,最终只能将整个系统全部启动起来,然后对某一个功能进行测试,那么对于一个可测试性好的系统来说,应该先可以对各个子模块进行测试。然后才进行集成性的测试。

那么怎么样才能写出可测试性好的代码呢

首先,这段代码应该符合设计模式,并且要契合诸如SOLID原则等,比如单一职责原则的代码保证精简。倒置依赖原则的代码,高层就不会依赖于底层实现。

在代码中,我们更是可以看Spring这类IOC框架,其内部的注入,就是因为Spring帮助我们创建对象,并且在类中组装。

完全符合代码理应组装,而不应该在类内部直接创建。

public class TodoItemService {

private final TodoItemRepository repository;

 

public TodoItemService(final TodoItemRepository repository) {

this.repository = repository;

}

}

诸如上面的TodoItem Repository,就可以利用mock创建一个,然后塞入Service对象之中。

其次,在static方法之中,不要涉及到任何的业务代码,虽然static很方便,但是对于测试来说,如果一旦使用了测试,就没法进行mock了。所以static方法之中,理应只存在基础库。

除此外,需要注意,不能直接mock的代码还有Singleton,全局模式这俩者,也需要在编写的时候注意。

除此外,还有第三方代码集成。

对于如何涉及到其他依赖。其他第三方代码,一般来说,我们有两种处理方式,一种是将其抽出,形成static代码。

要么是通过代码隔离,首先定义接口,然后在具体实现中,书写不同的第三方代码调用。就比如

interface TodoItemRepository {

}

class FileTodoItemRepository implements TodoItemRepository {

}

class DbTodoItemRepository implements TodoItemRepository {

}

这样通过定义一个接口,从而隔离不同的第三方代码,从而方便测试。

最后一点是,第三方的代码会回调我们的代码

这种情况下,我们的处理方式一般都是在回调函数中,直接调用我们预先封装好的一个函数,这样的话,就可以针对这个封装好的函数进行调用测试。

这也正是常说的防腐层的概念。

那么我们这里,说了实际上影响测试的主要因素,是在于多个子模块之中,对于子模块代码的书写时,没有兼顾测试性导致只能做整体的测试。

为此我们我说了如何去编写可以测试的代码。

比如组装多于继承。

Static中只存在工具类代码。

多封装接口,使用接口来mock测试。

发表评论

邮箱地址不会被公开。 必填项已用*标注