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. .NET Core的介绍

    ASP.NET5应用程序默认使用.net core来构建应用程序,.net core是一个小的,优化过的.net运行时应用程序. 1. 什么是的.NET Core .NET Core 5 是一由模块化 ...

  2. SQL server 如何修改登录名和密码

    No :1 启动SQL Server Management Studio,用windows登录进入: No :2 在左侧对象资源处理器中找到根节点,也就是你安装sqlserver时注册的服务器名称.然 ...

  3. move file create directory.

    If we want to move file to the directory that does not exist,and if we perform a File.Move,it will r ...

  4. OC - 22.隐式动画

    简介 每个UI控件,默认自动创建一个图层(根图层),即每个UI控件对应于至少一个图层 每一个UIView内部都默认关联着一个CALayer,我们可用称这个Layer为Root Layer(根层)   ...

  5. 对 const char* const &a 的理解

    定义中用到&是独立引用. 比如: char i; char &a=i; 表示a是i的一个单独引用. 当有i='a'时,也有a='a'; 当有a='c'时,也有i='c'; 两个变量的标 ...

  6. visual studio中验证控件的使用

    1.RequiredFieldValidator:验证一个必填字段,如果这个字段没填,那么,将不能提交信息. RequiredFieldValidator控件中,主要设置三个属性: (1)ErrorM ...

  7. Json串到json对象的转换

    JSON(JavaScript Object Notation) JS对象符号 是一种轻量级的数据交换格式 JavaScript eval()函数实现 (一) 标准格式 function JsonFo ...

  8. jsonp是什么以及jsonp的使用

    1概述 Jsonp(JSON with Padding)是资料格式 json 的一种“使用模式”,可以让网页从别的网域获取资料.由于同源策略,一般来说位于 server1.example.com 的网 ...

  9. LCD驱动学习笔记

    通过这几天的学习发现驱动的框架感觉都差不多,一般分为以下几个步骤: 分配一个结构体 struct x *x = amlloc(); 设置结构体的参数 硬件寄存器 file_operations 注册 ...

  10. 黑马程序员—C语言的特点和关键字

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- C语言的简介 一. C语言具有下列特点: C语言既具有低级语言直接操纵硬件的特点,又具有高级语言 ...