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,一般一个 ...
随机推荐
- Codefroces B. New Skateboard
B. New Skateboard time limit per test 1 second memory limit per test 256 megabytes input standard in ...
- (JavaScript基础向)日常小发现:forEach等函数的第二个参数的用法
forEach函数用得平时用得比较多,但是从来没想到forEach函数还有第二个参数. 这里是菜鸟教程对forEach函数的详细说明:forEach的详细说明. 如上图,forEach函数有第二个参数 ...
- IDLE的自动补全功能
IDLE的自动补全功能位于:Edit→Show Completions,但每次需要补全的时候都需要点击一次,虽然IDLE提供了一个快捷键(Ctrl + Space),但实测无效.具体操作如下图
- Struts2+Spring+Hibernate step by step 06 整合Hibernate
注:该系列教程.部分内容来自王健老师编写ssh整合开发教程 Hibernate是一款优秀的ORM(Object Relation Mapping-对象关系映射图)工具.与Struts.Spring项目 ...
- pdnsd 解析原理
apt install dnsmasq dnsmasq-fullvim /etc/dnsmasq.conf vim /etc/pdnsd.conf killall pdnsdpdnsd -c /etc ...
- Windows Server 2016 关闭Internet Explorer增强的安全配置
Windows Server 2016 关闭Internet Explorer增强的安全配置 IE11 默认启用 Internet Explorer 增强的安全配置,浏览网页时这个提示十分频繁,是不是 ...
- Mahout应用
不多说,直接上干货! Mahout作为Apache基金会的顶级项目之一,Mahout的应用也极其广泛,一般分为商业应用和学术应用. 在商业应用中,Adobe AMP公司使用Mahout的聚类算法把用户 ...
- Vue的style与class
1. style 可以通过 :style="{height:`${heightData.main}px`}" 实现样式的动态绑定, style绑定的是一个对象,多个样式时用“,”隔 ...
- BZOJ3529: [Sdoi2014]数表(莫比乌斯反演,离线)
Description 有一张 n×m 的数表,其第 i 行第 j 列(1 <= i <= n, 1 <= j <= m)的数值为 能同时整除 i 和 j 的所有自然数之和.给 ...
- windows防火墙开放zabbix端口(批处理)
windows系统在防火墙开启的情况下,打开zabbix端口(10050与10051) 可以手动添加规则,也可以使用批处理生成. 一.下面先介绍批处理 netsh advfirewall firewa ...