Java反射学习总结终(使用反射和注解模拟JUnit单元测试框架)
转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持!
本文是Java反射学习总结系列的最后一篇了,这里贴出之前文章的链接,有兴趣的可以打开看看。
http://blog.csdn.net/a396901990/article/category/2302221
本文介绍了如何利用反射和注解去简单的模拟JUnit4单元测试框架,之所以选择JUnit4是因为4.0以后最大的改进就是使用了注解。需要注意的是这里并不是完全的模拟,只是简单实现了一下Runner类和JUnit注解相关的工作流程。所以本文的主要目的是介绍反射和注解的使用。废话不多说,直接进入正文。
首先来看一个Junit单元测试的小例子:
先定义一个简单的类,里面只有一个add计算加法的方法和一个divide计算除法的方法,divide方法需要判断除数不能为0否则抛出异常。
public calculate {
- add( a, b) {
- a + b;
- divide( a, b) Exception {
- ( == b) {
- Exception();
- }
- a / b;
- }
- }
接着写一个简单的JUnit测试类,对他进行单元测试
import org.junit.Assert.*;
- org.junit.After;
- import import public calulateTest {
- calculate cal;
- before() Exception {
- cal = calculate();
- );
- System.out.println(
- after() Exception {
- addTest() {
- System.out.println( result = cal.add(, );
- , result);
- }
- (expected = Exception.)
- div() Exception {
- System.out.println( , );
- }
- }
执行结果为:
before test
do add test
after test
------------------
before test
do divide test
after test
下面我们就用反射和注解的知识来模拟JUnit对于上面例子的实现。
这里先不着急看代码,先看梳理一下思路。
1.JUnit只可以知道一件事,那就是待测试类的名字,其他的一概不知。所以我们只能利用测试类的名字作为切入口
2.通过测试类的名字,使用反射去获取他的Class对象
3.然后通过该Class对象获得当前类中所有方法的Method数组
4.遍历这个Method数组,取得每一个Method对象
5.调用每一个Method对象的isAnnotationPresent(Annotation.class)方法,判断该方法是否被指定注解所修饰
6.本例中根据不同的注解,来判断调用方法的顺序。
7.如果Test注解有属性的话,则判断方法执行后的返回值,如果返回值等于预期的注解属性也就是expected = Exception.class则测试通过。
8.最后还有一个assertEquals方法,他去判断预期值和实际值是否相等来决定测试是否通过。
大致的思路有了,我们就可以开始模拟它了。
首先定义3个注解,分别是Before,Test,After。如果对于定义注解不清楚的同学请看我之前写的文章。
@Target
@Retention
public Before {
- }
@Target
@Retention
public Test {
- Class<? Object> expected() String.;
- }
@Target
@Retention
public After {
- }
三个很简单的注解,都标注只能修饰方法,保留策略为运行时,这样可以被反射读取到。
只有Test注解中定义了一个属性,类型可以为任何类型的Class对象,默认值为String类型的Class对象。
接下来定义我们模拟的JUnit类,这里为了方便我将所有能用到的都写在一个MyJUnit类中。他对外只有一个构造方法和一个run方法。还有一个对比用的assertEquals方法
public MyJUnit {
- List<Method> beforeMethod;
- List<Method> afterMethod;
- List<Method> testMethod;
- List<Exception> exceptions;
- Object object;
- Class<?> testClass;
- MyJUnit(String testName) {
- ();
- {
- beforeMethod = ArrayList<>();
- ArrayList<>();
- testMethod = ArrayList<>();
- ArrayList<>();
- testClass = Class.forName(testName);
- getAllMethods();
- (Exception e) {
- getAllMethods() {
- (Method m : methods) {
- (m.isAnnotationPresent(Before.)) {
- (m.isAnnotationPresent(After.)) {
- (m.isAnnotationPresent(Test.)) {
- run() {
- (Method method : testMethod) {
- runTest(method);
- (exceptions.size() == ) {
- );
- } {
- (Exception e : exceptions) {
- System.out.println();
- );
- e.printStackTrace();
- runTest(Method method) {
- {
- runBefores();
- (Exception e) {
- e.getMessage();
- RuntimeException(
- runAfters() Exception {
- (Method m : afterMethod) {
- Object[] {});
- }
- runBefores() Exception {
- (Method m : beforeMethod) {
- m.invoke(object, Object[] {});
- runTestMethod(Method method) {
- passCheck = ;
- {
- Test testAnnotation = method.getAnnotation(Test.);
- (testAnnotation.expected().newInstance() Exception) {
- ;
- }
- (Exception e) {
- (passCheck) {
- ;
- } {
- addExceptions(Exception e) {
- assertEquals(Object expected, Object actual) {
- (expected.equals(actual)) {
- ;
- } {
- Exception());
- }
- }
注解和JUnit类都定义好后可以写测试的方法了,和之前的测试方法没有区别,只是这次导包导入的都是我们自定义的包。
import gxy.test.Junit.MyJUnit.*;
- public MyCalulateTest {
- Calculate cal;
- before() Exception {
- Calculate();
- System.out.println();
- after() Exception {
- System.out.println(
- addTest() {
- result = cal.add(, );
- assertEquals(, result);
- (expected = Exception.)
- divTest() Exception {
- , );
- }
- }
为了检验测试效果,这里对于addTest的方法中assertEquals方法传入的预期值和实际值不同。
下面看最后的运行类。
public main(String[] args) Exception {
- MyJUnit myJUnit = MyJUnit();
- }
只有2行代码,传入需要测试的类的名字,然后执行run方法。
测试结果:
------------------
before test
do add test
after test
------------------
before test
do divide test
after test
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
测试不通过,错误的内容为:
java.lang.Exception: 预期值与实际值不相等
at gxy.test.Junit.MyJUnit.assertEquals(MyJUnit.java:139)
at gxy.test.Junit.MyCalulateTest.addTest(MyCalulateTest.java:26)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at gxy.test.Junit.MyJUnit.runTestMethod(MyJUnit.java:119)
at gxy.test.Junit.MyJUnit.runTest(MyJUnit.java:85)
at gxy.test.Junit.MyJUnit.run(MyJUnit.java:66)
at gxy.test.Junit.FinalTest.main(FinalTest.java:13)
本文只是简单的模拟了一下在JUnit中反射和注解的使用,而且在很多框架中很多都利用了反射和注解这对黄金组合来实现一些如权限判断,调用等等很多功能。所以说反射还是值得好好学习和研究的。
反射学习总结系列博文断断续续写了一个多月,这篇是最后一篇了。通过这一个月的学习对反射的基本概念和使用算是有了一个了解,有时间还需要深入的学习。
这里需要提一下,学习的资料主要是从网上下的系列视频。主要借鉴了其中中的思路和一些概念类的东西,但是文章中的例子都是我自己写的。最后向大家推荐一下这个视频吧,不是做广告,讲的确实不错,讲课的老师叫张龙,口齿清晰讲的很深入。在大学时看的马士兵的视频,比较适合入门,这个适合晋级。再想继续晋级就得看书了,哈哈。
由于一些烂七八糟的原因我就不提供这个视频的下载地址了,如果需要请自己上网搜,或者留下邮箱我给链接发过去。
最后把本例的代码上传了,导入就可以运行。点击打开下载链接
Java反射学习总结终(使用反射和注解模拟JUnit单元测试框架)的更多相关文章
- Java高级特性 第10节 IDEA和Eclipse整合JUnit测试框架
一.IDEA整合Junit测试框架 1.安装插件 打开File菜单的下拉菜单settings[设置] : 点击左侧Plugins[插件]菜单 在输入框中输入JUnitGenerator 2.0,点击I ...
- Java - Junit单元测试框架
简介 Junit : http://junit.org/ JUnit是一个开放源代码的Java语言单元测试框架,用于编写和运行可重复的测试. 多数Java的开发环境都已经集成了JUnit作为单元测试的 ...
- Android(java)学习笔记106-2:反射机制
1.反射机制: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为 ...
- Android(java)学习笔记46:反射机制
1. 反射机制: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称 ...
- JAVA自动化之Junit单元测试框架详解
一.JUnit概述&配置 1.Junit是什么? Junit是一个Java 编程语言的开源测试框架,用于编写和运行测试.官网 地址:https://junit.org/junit4/ 2.Ma ...
- c#中@标志的作用 C#通过序列化实现深表复制 细说并发编程-TPL 大数据量下DataTable To List效率对比 【转载】C#工具类:实现文件操作File的工具类 异步多线程 Async .net 多线程 Thread ThreadPool Task .Net 反射学习
c#中@标志的作用 参考微软官方文档-特殊字符@,地址 https://docs.microsoft.com/zh-cn/dotnet/csharp/language-reference/toke ...
- Java基础学习总结(45)——JAVA单元测试工具比较
1.简介 jtest是parasoft公司推出的一款针对java语言的自动化白盒测试工具,它通过自动实现java的单元测试和代码标准校验,来提高代码的可靠性.Jtest先分析每个java类,然后自动生 ...
- Java Junit测试框架
Java Junit测试框架 1.相关概念 Ø JUnit:是一个开发源代码的Java测试框架,用于编写和运行可重复的测试.它是用于单元测试框架体系xUnit的一个实例(用于java语言).主要 ...
- Java 工具 JUnit单元测试
Java 工具 JUnit单元测试 @author ixenos 1.1. JUnit单元测试框架的基本使用 一.搭建环境: 导入junit.jar包(junit4) 二.写测试类: 0,一般一个 ...
随机推荐
- AutoCAD 许可管理器不起作用,或未正确安装,现在将关闭
问题描述 重新安装了也还是这样,而且第二次打开都跳不出申请码界面就关闭了. 问题原因,初步认为:AutoCAD 在首次弹出申请激活类型的类型时,直接选择了网络激活,而且没有激活成功.再想通过激活码的方 ...
- jquery表格简单插件
1.一直对jquery插件感觉非常神奇.今天动手写了一个超级简单的案例. 2.效果 3.体会 a.jquery插件编写能力. 须要具备一定js能力的编写.还有写css样式的运用:希望以后这方面会有提高 ...
- Android自定义视图
Android框架为我们提供了大量的视图类来帮助我们做好展示信息以及同用户进行交互的工作.然后有时候,我们的app或许需要一些在Android内建视图之外特殊的视图,那么此时我们就需要自定义视图.下面 ...
- thinkphp最简单路由
thinkphp最简单路由 一.总结 1.路由应用场景(前台要,后台不要):前台所有人都可以看,所以前台的话设置路由,后台的话并不是所有人都进去,所以不需要设置路由 2.模块分离来实现路由场景应用:前 ...
- 初步使用RecyclerView实现瀑布流
先看效果 关于RecyclerView,真的是很强大. 个人觉得主要方便的地方是 1.直接可以设置条目布局,通过setLayoutManager LinearLayoutManager:线性布局,横向 ...
- 28.Node.js 函数和匿名函数
转自:http://www.runoob.com/nodejs/nodejs-module-system.html 在JavaScript中,一个函数可以作为另一个函数的参数.我们可以先定义一个函数, ...
- 利用安卓手机的OTG共享有线网络
利用安卓手机的OTG共享有线网络 安卓手机有些是支持OTG的,OTG的显著特点就是手机能给外部设备供电,而且能交换数据. 那么,没有OTG功能的手机能不能给弄个OTG出来呢?当然可以,原因很简单,既然 ...
- python登录验证程序
自己写的一个python登录验证程序: 基础需求: 让用户输入用户名密码 认证成功后显示欢迎信息 输错三次后退出程序 升级需求: 可以支持多个用户登录 (提示,通过列表存多个账户信息) 用户3次认证失 ...
- HTML中input标签maxlength属性的妙处
HTML中的input标签可是很常用的. HTML本身也非常简单,就是若干标签,每个标签有若干属性. 我在学习HTML的过程中,也没有太过重视. 今年,在写前端表单验证的时候,发现maxlength这 ...
- hibernate hbm.xml配置映射
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...