可测试性战术

定义:软件可测试性是指通过测试(通常是基于运行的测试)揭示软件缺陷的容易程度。在开发设计良好的系统的成本中,至少有40%是用在了测试上。如果软件设计师能够降低此成本,则将会收到巨大的回报。

要想对系统进行正确的测试,必须能够“控制”每个组件的内部状态及其输入,然后“观察”其输出。这通常通过使用“测试工具”进行,这是一种专门设计的软件,用于执行所测试的软件。这可能会如同在各种接口上回放已记录的数据一样简单,也可能会像测试发动机的燃烧室一样复杂。

可测试性战术:可测试性战术的目标是允许在完成软件开发的一个增量后,较轻松地对软件进行测试。我们对两类用于测试的战术进行讨论:提供输入并捕获输出;内部监视。

输入输出:1.记录/回放。记录/回放是指捕获跨接口的信息,并将其作为测试专用软件的输入。在正常操作中跨一个接口的信息保存在某个存储库中,它代表来自一个组件的输出和传到一个组件的输入。记录该信息使得能够生成对其中一个组件的测试输入,并保存用于以后的比较的测试输出。

数据库的连接就是一个很好的例子,将数据库的名称密码作为接口信息存储,来测试是否可以连接到数据库:

public static Connection getConn () {
Connection conn = null;

try {
Class.forName("com.mysql.jdbc.Driver");//加载驱动
conn = DriverManager.getConnection(db_url, db_user, db_pass);
} catch (Exception e) {
e.printStackTrace();
}

return conn;//返回了产生的Connection对象
}

2.将接口与实现分离。将接口与实现分离允许实现的代替,以支持各种测试目的。点位实现允许在缺少被占位的组件时,对系统的剩余部分进行测试。用一个组件代替某个专门的组件能够使被代替的组件充当系统剩余部分的测试工具。

设计模式,里面有这个配置文件

策略模式:
class Client
{
public static void main(String args[])
{
Person mc=new Person((TravelStrategy)XMLUtil.getBean());
mc.travel();
}
}

配置文件:
<?xml version="1.0"?>
<config>
<className>TrainStrategy</className>
</config>

只要简单的修改配置文件里的一个参数,就可以测试结果,很方便

3.特化访问路线/接口。具有特化的测试接口允许通过测试工具并独立于其正常操作,来捕获或指定组件的变量值。例如,可以通过特化的接口提供元数据,测试工具利用该接口推动其活动。应该将特化的访问路线和接口与针对所要求功能的访问路线和接口分离开。使构架中的测试接口分层意味着可以在架构的任何层次上应用测试用例,并且已经具备观察响应的测试功能。

面向接口编程和面向对象编程:

面向对象开发:
UserDao dao = new UserDao();

假设项目开发中dao层的技术要升级改造,那么面向对象开发有两种实现方式

将UserDao中的代码删除,全部重写,但是方法名称不允许改变,为了不影响其他层,如service层调用dao的方法
创建一个新的类,如:UserDaoTwo 所有的方法名称照搬,用新技术重写方法体中的内容,但是需要调用dao层的位置,要全部更换为新的类,new UserDaoTwo();

面向接口编程:

UserDao dao = new UserDaoImpl();

1.项目需要升级改造时:

不需要修改原来的类,只要创建一个新的类,实现这个接口,以前的方法全部都有,只要重写方法体即可,不会漏写
为了不在调用dao处,修改多次,可以写为UserDao dao = 工具类.getImpl(); 这时如果我们项目升级过程中更改了实现类,只需要在工具类中修改一次,项目中就全部修改了
这时我们又发现,工具类中如果给多个接口返回实现类,就有如下代码冗余的问题:

public static Object getBean(){
return new UserDaoImpl();
}
public static Object getCategoryBean(){
return new CategoryDaoImpl();
}
public static Object getFavoriteDaoImpl(){
return new FavoriteDaoImpl();
}

这时就出现了,面向接口编程的最终版:

UserDao dao = 工具类.getImpl(id);在创建实现类的时候,传入一个id. 在配置文件中,根据id唯一标识一个实现类的全限定类名.工具类中只需要根据这个id去配置文件中获得内容,反射 动态实例化创建对象就好了.以后,再修改升级功能时,只需要在配置文件中修改全限定类名就好了

public class BeanFactoryUtils {
public static Object getBean(String id) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
//1.根据传入id 获得配置文件中已经配置好的value属性 ==>全限定类名
ResourceBundle bundle = ResourceBundle.getBundle("bean");//bean为配置文件
String className = bundle.getString(id);
//2.反射 动态实例化对象 ==>>必须有全限定类名 ==>> 字符串 ==>> 抽取到配置文件中
Class clazz = Class.forName(className);
return clazz.newInstance();
}
}

内部监视器:组件可以维持状态、性能负载、容量、安全性或其他可通过接口访问的信息。此接口可以是该组件的一个永久接口,也可以是通过instrumentation技巧临时引入的接口,如面向方面编程或预处理宏。一个常见的技巧就是当监视状态被激活时记录事件。监视状态实际上会增加测试工作,因为随着监视的关闭,可能必须重复测试。尽管额外测试需要一定的开销,但这却使组件活动的可见性得以提高,这样做是值得的。

 

内部监视器:
错误警告,报错,比方说一些I/O流错误了啥的
在执行文件的时候就可以进行测试,提醒哪里出错了,不足就是加了监视器代码,执行代码肯定会加长时间,但是相对于执行后代码出错,然后再亡羊补牢写测试代码找源代码中的错误,就方便多了
就好像平常写代码,用那个断点查看代码输出,如果把代码写完在回来看就无从下手

下面实例检测输入的值是否错误,如果错误则抛出异常。

异常通过 catch 语句捕获,并输出自定义信息

<p>请输入 5 和 10 之间的一个数:</p>
<input id="demo" type="text">
<button type="button" onclick="myFunction()">检测输入</button>
<p id="message"></p> <script>
function myFunction() { var message, x;
message = document.getElementById("message");
message.innerHTML = "";
x = document.getElementById("demo").value;
try { if(x == "") throw "为空";
if(isNaN(x)) throw "不是一个数字";
if(x > 10) throw "太大了";
if(x < 5) throw "太小了";
}
catch(err) {
message.innerHTML = "输入的值 " + err; }
}
</script>

参考链接:https://www.jianshu.com/p/344c69a14d71

 




原文地址:https://www.cnblogs.com/cuijunfeng/p/12400393.html