可测试性战术分析

  本篇博客参考《信息领域热词分析》,设计实现可测试性战术。

  首先我们要了解一下可测试性,软件可测试性是指通过测试(通常是基于运行的测试)揭示软件缺陷的容易程度。

  接下来就介绍在项目开发中运用的可测试性战术:

  1.面向对象编程

  作为一名软件工程的学生,我们都知道编码原则:

  • 单一责任原则
  • 开放/封闭原则
  • 里氏代换原则
  • 接口分离原则
  • 依赖反转原则

  不论是在爬虫爬取信息阶段,还是热词统计阶段,还有最后的可视化展示,都离不开这些原则。尤其是遵循了单一职责原则和接口分离原则后,面向接口编程,

  每一个函数或者对象,都只完成单一的功能,主函数只对其进行调用或传参,可测试性就会大大提高,这些原则会引导我们持续重构。

  单一职责:

interface UserOpr2 {
    boolean updatePassword(User user, String password);
    boolean updateUserInfo(User user);
}

class UserOprImpl2 implements UserOpr2 {

    @Override
    public boolean updatePassword(User user, String password) {
        user.setPassword(password);
        // update password
        return true;
    }

    @Override
    public boolean updateUserInfo(User user) {
        // update user info
        return true;
    }
}
View Code

  修改密码和修改名字分离开来,也就是把修改密码和修改名字都当做独自的职责处理,这样子就很清晰明了,你调用哪个方法,就很明确的知道这个方法是实现什么逻辑。

  接口隔离(提高了系统的内聚性,减少了对外交互,降低了系统的耦合性):

 

package org.byron4j.cookbook.designpattern.segregation;

/**
 * 施乐公司系统机器接口
 */
public interface IMachine {
    /**
     * 打印
     */
    public void print();

    /**
     * 装订
     */
    public void staple();

    /**
     * 扫描
     */
    public void scan();

    /**
     * 复印
     */
    public void photoCopy();
}

package org.byron4j.cookbook.designpattern.segregation;

public class XeroxMachine implements  IMachine {
    @Override
    public void print() {
        System.out.println("打印任务...");
    }

    @Override
    public void staple() {
        System.out.println("装订任务...");
    }

    @Override
    public void scan() {
        System.out.println("扫描任务...");
    }

    @Override
    public void photoCopy() {
        System.out.println("复印任务...");
    }
}
View Code

  2.使用设计模式

  上学期我们学习过设计模式这门课程,设计模式其实是代码经验的总结。

  比如策略模式,策略模式定义了一组算法,将每个算法都封装起来,并使它们之间可以互换。这个模式让法算法的变化独立于客户端的调用。

  策略模式优点:1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。

  

package com.hotwords.dao;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
 
import com.hotwords.entity.entity;
 
public class dao {
    public List<entity> list1(){
        List<entity> list =new ArrayList<entity>();
        try {
            // 加载数据库驱动,注册到驱动管理器
            Class.forName("com.mysql.jdbc.Driver");
            // 数据库连接字符串
            String url = "jdbc:mysql://localhost:3306/xinwen?useUnicode=true&characterEncoding=utf-8";
            // 数据库用户名
            String username = "root";
            // 数据库密码
            String password = "893225523";
            // 创建Connection连接
            Connection conn = DriverManager.getConnection(url, username,
                    password);
            // 添加图书信息的SQL语句
            String sql = "select * from final_hotword";
            // 获取Statement
            Statement statement = conn.createStatement();
   
            ResultSet resultSet = statement.executeQuery(sql);
   
            while (resultSet.next()) {
                entity book = new entity();
                book.setHotwords(resultSet.getString("热词"));
                book.setNum(resultSet.getString("次数"));
                list.add(book);
            }
            resultSet.close();
            statement.close();
            conn.close();
}catch (Exception e) {
    e.printStackTrace();
}
        return list;
    }
    //
    public List<entity> list2(){
        List<entity> list =new ArrayList<entity>();
        try {
            // 加载数据库驱动,注册到驱动管理器
            Class.forName("com.mysql.jdbc.Driver");
            // 数据库连接字符串
            String url = "jdbc:mysql://localhost:3306/xinwen?useUnicode=true&characterEncoding=utf-8";
            // 数据库用户名
            String username = "root";
            // 数据库密码
            String password = "893225523";
            // 创建Connection连接
            Connection conn = DriverManager.getConnection(url, username,
                    password);
            // 添加图书信息的SQL语句
            String sql = "select * from website";
            // 获取Statement
            Statement statement = conn.createStatement();
   
            ResultSet resultSet = statement.executeQuery(sql);
   
            while (resultSet.next()) {
                entity book = new entity();
                book.setHotwords(resultSet.getString("热词"));
                book.setExplain(resultSet.getString("解释"));
                book.setWebsite(resultSet.getString("网址"));
                list.add(book);
            }
            resultSet.close();
            statement.close();
            conn.close();
}catch (Exception e) {
    e.printStackTrace();
}
        return list;
    }
}
View Code

  

    

   3.特定化访问接口

  面向接口编程有两层含义:类级别,面向接口编程; 方法级别,面向函数接口编程。

  既定的接口具有自我描述性,并能够促进代码的重用性,接口可以提供一种信息,告诉外部一个类需要实现哪些方法。还有助于稳定不同类之间的通信方式,减少了继承两个对象的过程中出现的问题。

  比如 A 对象依赖 B 对象里的 M 方法,而 M 方法会从数据库里读取数据。那么 A 就不要直接依赖 B 的实体类,而引用 B 的接口。 当对 A 编写单测时,只要注入 B 的 接口实现即可。 同理,方法中含有 service 调用时,不要直接依赖 service 调用,而是依赖函数接口,在函数接口中传递 service 调用,如上面的做法。

  

@FunctionalInterface
public interface Predicate<T>{
    boolean test(T t);
}
public static <T> List<T> filter(List<T> list, Predicate<T> p) {
    List<T> results = new ArrayList<>();
    for(T s: list){
        if(p.test(s)){
            results.add(s);
        }
    }
    return results;
}
Predicate<String> nonEmptyStringPredicate = (String s) -> !s.isEmpty();
List<String> nonEmpty = filter(listOfStrings, nonEmptyStringPredicate);

 

原文地址:https://www.cnblogs.com/Aduorisk/p/12397255.html