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,一般一个 ...
随机推荐
- J2msi 自己制作的把exe打成安装包简易GUI程序
因为wix是用命令行执行的,操作比较麻烦,所以自己写了个wix生成安装包的图形操作程序, 原理很简单,主要用java 来执行 wix 的heat .candle 和 light 命令 ,最后生成安装文 ...
- 分享一个css3学习使用的选择器手册
http://www.haorooms.com/tools/css_selecter/
- PatentTips - Transparent unification of virtual machines
BACKGROUND Virtualization technology enables a single host computer running a virtual machine monito ...
- 公告:本博客搬迁到:http://www.courtier.cc
公告: 您好,本人意见本博客搬迁到:http://www.courtier.cc
- ubuntu终端sudo java提示“command not found”解决办法
我在ubuntu 12.04里想启动一个java程序,sudo java -jar xxx.jar,但是结果提示sudo:java:command not found. Ubuntu下用sudo运行j ...
- JS ajax 应用 (下拉列表联动)
<script language="javascript"> var http_request=false; function send_request( ...
- 1.26 Python知识进阶 - 继承
继承 继承(Inheritance)是面向对象的程序设计中代码重要的主要方法.继承是允许使用现有类的功能,并在无需重新改写原来的类的情况下,对这些功能进行扩展.继承可以避免代码复制和相关的代码维护等问 ...
- ArcGIS小技巧——提取面要素的质心点
如下图,现在要做这样一件事,提取面图层中每一个图斑的质心点,然后使用质心点提取图层中的一个属性值,并在此基础上进行克里金插值,生成该属性的空间插值图.当然,今天这段文字主要简单说一下怎样提取面图层的质 ...
- linux下安装sar
本文转自(https://blog.csdn.net/qq_31391261/article/details/79419740) OS:centos6.5 操作步骤: 1)输入sar命令:sar -- ...
- Lamp(linux+apache+mysql+php)环境搭建
Lamp(linux+apache+mysql+php)环境搭建 .安装apache2:sudo apt-get installapache2 安装完毕后.执行例如以下命令重新启动apache:sud ...