JUnit软件测试技术(工具)

在项目中建立专门用户测试的包结构。

在Junit中,通过@Test注解,可以运行一个方法。

★ Junit注解说明

使用了@Test注解应该满足以下条件:

1) 必须是无参数的非静态方法。

2) 添加@Test注解的类,必须拥有一个无参数的公开构造

★ JUnit测试示例演示

1、运行完成后,可以在Junit的窗口上看到运行所用的时间和结果信息。

2、被测试程序的运行结果出现在控制台(Console)上。

“项目”代码:

package cn.hncu.user.dao.dao;
/**
* @author 陈浩翔
* @version 1.0 2016-5-4
*/
public interface UserDao {
public abstract void fun1()throws Exception;
public abstract void fun2();
public abstract void fun3();
}
package cn.hncu.user.dao.impl;

import cn.hncu.user.dao.dao.UserDao;

/**
* @author 陈浩翔
* @version 1.0 2016-5-4
*/
public class UserDaoImpl implements UserDao{
@Override
public void fun1() throws Exception {
System.out.println("fun1....");
}
@Override
public void fun2() {
System.out.println("fun2....");
}
@Override
public void fun3() {
System.out.println("fun3....");
}
}
package cn.hncu.user.dao.factory;

import cn.hncu.user.dao.dao.UserDao;
import cn.hncu.user.dao.impl.UserDaoImpl; /**
* @author 陈浩翔
* @version 1.0 2016-5-4
*/
public class UserDaoFactory {
public static UserDao getUserDao(){
return new UserDaoImpl();
}
}

随便写了几个输出。。。

下面的是测试代码:

package cn.hncu.test;

import org.junit.Test;

import cn.hncu.user.dao.dao.UserDao;
import cn.hncu.user.dao.factory.UserDaoFactory;
import cn.hncu.user.dao.impl.UserDaoImpl; /**
* @author 陈浩翔
* @version 1.0 2016-5-4
*/
//使用@Test的条件2:该类必须具有一个无参构造方法
public class TestUserDaoImpl {
UserDao dao = UserDaoFactory.getUserDao(); /**
* 测试fun1()方法
*/
//使用@Test的条件1:测试方法必须是非静态、无参
@Test
public void testFun1(){
try {
dao.fun1();
} catch (Exception e) {
e.printStackTrace();
}
} @Test
public void testFun2() {
dao.fun2();
} @Test
public void testFun3() {
dao.fun3();
} }

正确的演示结果:

错误的演示结果:(没有无参构造方法)

★ JUnit中的其它注解

@BeforeClass、@AfterClass、@Before、@After

package cn.hncu.test;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test; import cn.hncu.user.dao.dao.UserDao;
import cn.hncu.user.dao.factory.UserDaoFactory;
import cn.hncu.user.dao.impl.UserDaoImpl; /**
* @author 陈浩翔
* @version 1.0 2016-5-4
*/ public class TestUserDaoImpl2 {
UserDao dao = UserDaoFactory.getUserDao(); //注意要加static
@BeforeClass
public static void initFirst(){
System.out.println("finishEnd...");
} //在每次运行@Test方法之前,都会先运行这个@Before的方法
@Before
public void init(){
System.out.println("init...");
} @Test
public void testFun1(){
try {
dao.fun1();
} catch (Exception e) {
e.printStackTrace();
}
}
/*运行结果
finishEnd...
init...
fun1....
finish...
finishEnd...
*/ @Test
public void testFun2() {
dao.fun2();
}
/*运行结果
finishEnd...
init...
fun2....
finish...
finishEnd...
*/ @Test
public void testFun3() {
dao.fun3();
}
/*运行结果
finishEnd...
init...
fun3....
finish...
finishEnd...
*/ //在每次运行@Test方法之后,都会最后运行这个@After的方法
@After
public void finish(){
System.out.println("finish...");
} //注意要加static
@AfterClass
public static void finishEnd(){
System.out.println("finishEnd...");
} }

注解 ( Annotation )

★ 元数据

    所谓元数据就是数据的数据。也就是说,元数据是描述数据的。就象数据表中的字段一样,每个字段描述了这个字段下的数据的含义。
元数据可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。许多元数据工具,如XDoclet,将这些功能添加到核心Java语言中,暂时成为Java编程功能的一部分。
一般来说,元数据的好处分为三类:文档编制、编译器检查和代码分析。代码级文档最常被引用。元数据提供了一种有用的方法来指明方法是否取决于其他方法,它们是否完整,特定类是否必须引用其他类,等等。

★ 什么是注解

Java中的注解就是Java源代码的元数据,也就是说注解是用来描述Java源代码的。 基本语法就是:@后面跟注解的名称。

像前面演示的那几个都是注解。

★ Java中预定义注解

①Override:标识某一个方法是否正确覆盖了它的父类的方法。

(如果用了这个注解,但是父类中没有这个方法,就会报错)



②Deprecated:表示已经不建议使用这个类成员了。 它是一个标记注解。

(用了这个注解的,表示在下一个升级版本中,可能不会有这个方法了,但是会有类似功能的方法代替,会在注释中提出)

③SuppressWarnings:用来抑制警告信息。

(例如:压泛型的警告)



(这个是可以传参进去的,可以实现不同的功能)

自定义注解1

自定义注解的语法很简单,跟定义接口类似,只是在名称前面加上@符号。

★ 最简单的自定义注解

public @interface MyAnno {
}

★ 使用这个注解

和使用其他注解是一样的

@MyAnno
public class UserModel{
}

★ 为注解添加成员

//定义
public @interface MyAnno {
public String schoolName();
}
//使用
@MyAnno(schoolName="湖南城市学院")
public class UserModel{
}

★ 设置默认值

//定义
public @interface MyAnno {
public String schoolName() default "湖南城市学院";
}
//使用1
@MyAnno
public class UserModel{
}
//使用2
@MyAnno(schoolName="城院Java高手训练营")
public class UserModel{
}

对注解的注解

package cn.hncu.anno;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
public @interface MyAnno {
}

☆指定目标 Target

在了解如何使用Target 之前,需要认识另一个类,该类被称为ElementType (通过API详细学习) ,它实际上是一个枚举。这个枚举定义了注释类型可应用的不同程序元素。

//如果都不写,就是随便在哪里都可以用

@Target({ ElementType.TYPE, ElementType.METHOD}) 

//这个注解可以在哪里用,TYPE-可以在类上面用,METHOD-可以在方法上用

☆设置保持性 Retention

RetentionPolicy (通过API详细学习)枚举类中定义了3种注解保持性,分别决定了Java 编译器以何种方式处理注解。

@Retention(RetentionPolicy.RUNTIME)

//运行时VM虚拟机也能识别这个注解,这个注解一直存在

@Retention(RetentionPolicy.SOURCE) 

//class文件中有这个注解,但是VM虚拟机运行时,忽略这个注解了。

(这是默认的)

☆添加公共文档 Documented

在默认的情况下在使用javadoc自动生成文档时,注解将被忽略掉。如果想在文档中也包含注解,必须使用Documented为文档注解。

☆设置继承 Inherited

在默认的情况下,父类的注解并不会被子类继承。如果要继承,就必须加上Inherited注解。

如何读取注解

要读取注解的内容,就需要使用反射的技术。

注意:要想使用反射得到注释信息,必须用@Retention(RetentionPolicy.RUNTIME)进行注解。

    /**
* 分别读取类上的@MyAnno注解 和 方法上的@MyAnno注解
*/
@Test
public void readAnno(){
//※※注意:MyAnno注解定义时,必须指定它的保持性为 RUNTIME,否则下面是读取不出注解的 //以下方式是读取“声明在类上的”MyAnno注解
Class c = UserModel.class;
//boolean boo = c.isAnnotationPresent(cn.hncu.anno.MyAnno.class);
//boolean boo = c.isAnnotationPresent(MyAnno.class);
boolean boo = (c.getAnnotation(MyAnno.class)!=null);
System.out.println(boo); //以下方式是读取“声明在方法上的”MyAnno注解
Method ms[] = c.getDeclaredMethods();
for(Method m:ms){
if(m.isAnnotationPresent(MyAnno.class)){
System.out.println(m.getName()+"方法上有@MyAnno注解");
}
}
}

结果:

true
getAge方法上有@MyAnno注解
getId方法上有@MyAnno注解

类加载器

Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:

BootStrap, ExtClassLoader, AppClassLoader

    @Test
public void systemLoaderDemo(){
ClassLoader loader = Person.class.getClassLoader();
System.out.println(loader);//AppClassLoader
loader = loader.getParent();
System.out.println(loader);//ExtClassLoader
loader = loader.getParent();
System.out.println(loader);//null
}

因为BootStrap是最底层,用C写的,我们不能访问到,我们没有权限,所以输出就是null了。

类加载器也是Java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是java类,这正是BootStrap。

Java虚拟机中的所有类装载器采用具有父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指定一个父级类装载器对象或者默认采用系统类装载器为其父级类加载。

☆类加载器的委托机制

通过API认识ClassLoader类

当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?

首先当前线程的类加载器去加载线程中的第一个类。如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。

还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。

每个类加载器加载类时,又先委托给其上级类加载器。当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild方法,即使有,那有多个儿子,找哪一个呢?

对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的aa.jar包中后,运行结果为ExtClassLoader的原因。

演示不是classpath下的类,系统类加载器是无法加载的

Person类:

package cn.hncu;
/**
*
* @author 陈浩翔
*
* @version 1.0 2016-5-4
*/
public class Person {
private String name;
private int age; public Person() {
} public Person(String name, int age) {
this.name = name;
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} @Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
    @Test
public void loaderLocalClassDemo() throws ReflectiveOperationException{
Class c = Class.forName("cn.hncu.Person");
System.out.println(c);
Object obj = c.newInstance();
System.out.println(obj);
}

运行结果:

class cn.hncu.Person
Person [name=null, age=0]

再看:

我把Person.class移到d:\cn\hncu

//不是classpath下的类,系统类加载器是无法加载的---如果要加载,得自己写类加载器
@Test
public void loaderRemoteClassDemo() throws ReflectiveOperationException{
Class c = Class.forName("d:\\cn\\hncu\\Person.class");
System.out.println(c);
Object obj = c.newInstance();
System.out.println(obj);
}

结果:

挂了,不能运行了。

因为没有配置classpath。

对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的aa.jar包中后,运行结果为ExtClassLoader

必须是压.class文件,不要压缩.java文件。!!!!

package cn.hncu;

/**
*
* @author 陈浩翔
*
* @version 1.0 2016-5-4
*/
public class LoaderDemo {
public static void main(String[] args) {
LoaderDemo a = new LoaderDemo();
System.out.println(a);
} @Override
public String toString() {
return "随便演示。。。chx";
}
}

先按照这个命令打包这个.java

package cn.hncu;

/**
*
* @author 陈浩翔
*
* @version 1.0 2016-5-4
*/
public class LoaderDemo {
public static void main(String[] args) {
LoaderDemo a = new LoaderDemo();
System.out.println(a);
} @Override
public String toString() {
return "湖南城院。。。随便演示...chx";
}
//改了没用。已经不会运行这里的代码了。
}

大家看输出结果:

对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的aa.jar包中后,运行结果还是为ExtClassLoader。

也就是那三层从上到下,如果上面已经有那个类了,就不会运行下面的那个类:

BootStrap—>ExtClassLoader—>AppClassLoader(System classLoader)

大家再看看这个图,是不是感觉容易理解一些了:

Java---JUnita、注解与类加载器详解以及实例的更多相关文章

  1. Java类加载器详解

    title: Java类加载器详解date: 2015-10-20 18:16:52tags: JVM--- ## JVM三种类型的类加载器- 我们首先看一下JVM预定义的三种类型类加载器,当一个 J ...

  2. Java学习-007-Log4J 日志记录配置文件详解及实例源代码

    此文主要讲述在初学 Java 时,常用的 Log4J 日志记录配置文件详解及实例源代码整理.希望能对初学 Java 编程的亲们有所帮助.若有不足之处,敬请大神指正,不胜感激!源代码测试通过日期为:20 ...

  3. GLSL-几何着色器详解跟实例(GS:Geometry Shader)[转]

    [OpenGL4.0]GLSL-几何着色器详解和实例(GS:Geometry Shader) 一.什么是几何着色器(GS:Geometry Shader) Input Assembler(IA)从顶点 ...

  4. [转载] Java高新技术第一篇:类加载器详解

    本文转载自: http://blog.csdn.net/jiangwei0910410003/article/details/17733153 首先来了解一下字节码和class文件的区别: 我们知道, ...

  5. Java高新技术第一篇:类加载器详解

    首先来了解一下字节码和class文件的区别: 我们知道,新建一个Java对象的时候,JVM要将这个对象对应的字节码加载到内存中,这个字节码的原始信息存放在classpath(就是我们新建Java工程的 ...

  6. 类加载器详解 (转至http://blog.csdn.net/jiangwei0910410003/article/details/17733153)

    首先来了解一下字节码和class文件的区别: 我们知道,新建一个java对象的时候,JVM要将这个对象对应的字节码加载到内存中,这个字节码的原始信息存放在classpath(就是我们新建Java工程的 ...

  7. 深入理解Java虚拟机(四)——HotSpot垃圾收集器详解

    垃圾收集器 新生代收集器 1.Serial收集器 特点: 单线程工作,收集的时候就会停止其他所有工作线程,用户不可知不可控,会使得用户界面出现停顿. 简单高效,是所有收集器中额外内存消耗最少的. 没有 ...

  8. 注解@PostConstruct与@PreDestroy详解及实例

    Java EE5 引入了@PostConstruct和@PreDestroy这两个作用于Servlet生命周期的注解,实现Bean初始化之前和销毁之前的自定义操作.此文主要说明@PostConstru ...

  9. Spring 使用注解对事务控制详解与实例

    1.什么是事务 一荣俱荣,一损俱损,很多复杂的操作我们可以把它看成是一个整体,要么同时成功,要么同时失败. 事务的四个特征ACID: 原子性(Atomic):表示组成一个事务的多个数据库的操作的不可分 ...

随机推荐

  1. ASP.NET-FineUI开发实践-16(一)

    还是基础的东西,grid全选没有事件,给加个事件,除了需要会复制粘贴外还要点推荐那!   第一步:原理  事件被触发,方法被实现. 对于全选事件,被触发有两种方式可写,一个是通过原生extjs方式触发 ...

  2. UMEditor 二次开发技术实践

    许多项目都会或多或少的结合许多第三的组件,恰好,遇到了UMeditor富文本组件,因为它及其精简,功能强大,有专业团队维护,所以,我选择了它,而且它出色的完成项目中的全部功能的需求,对此,我说一下,二 ...

  3. c#读取文件

    你平时是怎么读取文件的?使用流读取.是的没错,C#给我们提供了非常强大的类库(又一次吹捧了.NET一番), 里面封装了几乎所有我们可以想到的和我们没有想到的类,流是读取文件的一般手段,那么你真的会用它 ...

  4. 更新xcode后插件失效问题——不针对特定版本的通用解决方法

    一.Xcode更新后插件失效的原理 1.每次更新Xcode后插件都会失效,其实插件都还在这个目录好好的躺着呢: ~/Library/Application Support/Developer/Shar ...

  5. GCD介绍(三): Dispatch Sources

    何为Dispatch Sources         简单来说,dispatch source是一个监视某些类型事件的对象.当这些事件发生时,它自动将一个block放入一个dispatch queue ...

  6. 2016.7.16equals的使用(一)

    class V{ private int a; V(int a){ rhis a=a; } public  boolean equals(int a,int b){ if(this.a equals( ...

  7. IOI1994 北京2008的挂钟 迭代加深

    总的来讲,这是一道很⑨的题,因为: (1)题目中有⑨个挂钟 (2)有⑨种操作方案 (3)这题因为解空间太小所以可以直接⑨重循环!! 这题可以用迭代加深搜索高效求解,剪枝的策略也很显然: >所求的 ...

  8. 【BZOJ3211】【并查集+树状数组】花神游历各国

    Description   Input   Output 每次x=1时,每行一个整数,表示这次旅行的开心度 Sample Input 4 1 100 5 5 5 1 1 2 2 1 2 1 1 2 2 ...

  9. 前端模板文件化jQuery插件 $.loadTemplates

    工作中使用前端模板引擎,如 artTemplate.jsRender,来替代拼接字符串. 可是直接把模板写在页面上会带来页面臃肿,模板无法重用,与 ASP.NET等后端语言语法冲突等问题. 所以将多个 ...

  10. 舵机的PWM控制学习随笔

    舵机的控制信号,对于脉宽调制信号的脉宽变换,常用的一种方法是采用调制信号获取有源滤波后的直流电压,但是需要50Hz(周期是20ms)的信号,这对运放器件的选择有较高要求,从电路体积和功耗考虑也不易采用 ...