利用反射模仿JUnit写一个自己的测试驱动类

发表于:2018-11-15 13:20

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:codingmyworld    来源:博客园

  package sample.runner;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Method;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  /**
  *
  * @author CodingMyWorld
  * 自定义测试驱动类
  */
  public class MyTestRunner {
  // 用于存放TestCase及其中的TestMethods
  private Map<Class<?>, List<Method>> mTestCases = new HashMap<Class<?>, List<Method>>();
  private static final String WARING_FMT = "警告: %s%n";
  private static final String ERROR_FMT = "错误: %s%n%s%n";
  // 增加一个测试用例类
  public MyTestRunner addTestCase(Class testcase) {
  List<Method> testMethods = findTestMethods(testcase);
  if (testMethods.isEmpty()) {
  System.out.format(WARING_FMT,
  "TestCase '" + testcase.getName() + "' 没有定义测试方法");
  } else {
  mTestCases.put(testcase, testMethods);
  }
  return this;
  }
  // 返回某个测试用例中的测试方法
  // 测试方法必须满足:1.方法名为testXxx 2.无参
  private List<Method> findTestMethods(Class<?> testcase) {
  // 得到类中定义的所有方法,包括private
  Method[] methods = testcase.getDeclaredMethods();
  List<Method> result = new ArrayList<Method>();
  for (Method method : methods) {
  if (method.getName().matches("test[A-Z\\d].*") && method.getParameterTypes().length == 0) {
  result.add(method);
  }
  }
  return result;
  }
  public void run() {
  if (mTestCases.isEmpty()) {
  System.out.format(WARING_FMT, "没有可运行的测试用例。");
  return;
  }
  int succeedTCNum = 0;
  System.out.format("开始执行。共有%d个测试用例%n", mTestCases.size());
  for (Class<?> testcase : mTestCases.keySet()) {
  // 1.构造实例
  Object instance = null;
  try {
  Constructor constructor = testcase.getDeclaredConstructor();
  constructor.setAccessible(true);
  instance = constructor.newInstance();
  } catch (NoSuchMethodException ex) {
  System.err.format(ERROR_FMT, testcase.getName() + "没有无参的构造器!", ex.getCause().getMessage());
  } catch (InvocationTargetException ex) {
  System.err.format(ERROR_FMT, testcase.getName() + "构造发生异常!", ex.getCause().getMessage());
  } catch (Exception ex) {
  System.err.format(ERROR_FMT, testcase.getName(), ex.getMessage());
  }
  if (instance == null) {
  continue;
  }
  System.out.format("%n==>TestCase:%s%n", testcase.getName());
  // 2.执行每个测试方法
  boolean isAllMethodSuccess = true;
  List<Method> methods = mTestCases.get(testcase);
  for (Method method : methods) {
  System.out.format("----方法%s%n", method.getName());
  try {
  method.setAccessible(true);
  method.invoke(instance);
  } catch (InvocationTargetException ex) {
  isAllMethodSuccess = false;
  System.err.format(ERROR_FMT, method.getName() + "方法发生异常!", ex.getCause().getMessage());
  } catch (Exception ex) {
  isAllMethodSuccess = false;
  System.err.format(ERROR_FMT, method.getName(), ex.getMessage());
  }
  }
  if(isAllMethodSuccess) {
  succeedTCNum++;
  System.out.format("<==完成!%n");
  }
  }
  System.out.format("%n执行完毕。共有%d个测试用例通过测试!", succeedTCNum);
  }
  }
  有了该驱动类,就可以同时对多个类进行测试了,例如要测试TestMap和TestSet这两个类
  package sample.map;
  import java.util.HashMap;
  import java.util.Map;
  /**
  *
  * @author CodingMyWorld
  */
  public class TestMap {
  //Map最常规的put与get
  private void test1() {
  Map map = new HashMap();
  map.put("1", "Monday");
  map.put("2", "Tuesday");
  map.put("3", "wednesday");
  map.put("4", "Thursday");
  System.out.println("size : " + map.size());
  System.out.println("map[\"2\"] : " + map.get("2"));
  }
  //Map中的键值不能重复
  private void test2() {
  Map map = new HashMap();
  map.put("1", "Mon.");
  map.put("1", "Monday");
  map.put("one", "Monday");
  System.out.println("size : " + map.size());
  System.out.println("map : " + map);
  }
  //遍历Map中的键值对
  private void test3() {
  Map map = new HashMap();
  map.put("1", "Monday");
  map.put("2", "Tuesday");
  map.put("3", "wednesday");
  map.put("4", "Thursday");
  for(Object key : map.keySet()) {
  System.out.println(key + " : " + map.get(key));
  }
  }
  }
   
  package sample.set;
  import java.util.HashSet;
  import java.util.Set;
  /**
  *
  * @author CodingMyWorld
  */
  public class TestSet {
  // 说明Set中存放的是对象的引用,不能有重复对象
  private void testElementStore() {
  Set set = new HashSet();
  String s1 = "hello";
  String s2 = s1;
  String s3 = "world";
  set.add(s1);
  set.add(s2);
  set.add(s3);
  System.out.println("set1 size : " + set.size());
  System.out.println("set1 : " + set);
  }
  // Set使用equals比较两个元素是否相等
  private void testElementEqual() {
  Set set = new HashSet();
  String s1 = "hello";
  String s2 = "hello";
  set.add(s1);
  set.add(s2);
  System.out.println("set2 size : " + set.size());
  System.out.println("set2 : " + set);
  }
  }

  我现在只需要在任何一个main方法中这么写就行了,比之前手动挨个调用方法方便了很多。
  public static void main(String[] args) {
  new MyTestRunner()
  .addTestCase(TestMap.class)
  .addTestCase(TestSet.class)
  .run();
  }
  最后,看到运行结果整齐的输出到控制台,心情大好so(≧v≦)o~~
  开始执行。共有2个测试用例
  ==>TestCase:sample.set.TestSet
  ----方法testElementStore
  set1 size : 2
  set1 : [hello, world]
  ----方法testElementEqual
  set2 size : 1
  set2 : [hello]
  <==完成!
  ==>TestCase:sample.map.TestMap
  ----方法test1
  size : 4
  map["2"] : Tuesday
  ----方法test2
  size : 2
  map : {1=Monday, one=Monday}
  ----方法test3
  3 : wednesday
  2 : Tuesday
  1 : Monday
  4 : Thursday
  <==完成!
  执行完毕。共有2个测试用例通过测试!

上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。
22/2<12
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号