All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
holmos.webtest.junitextentions.HolmosRunner Maven / Gradle / Ivy
package holmos.webtest.junitextentions;
import holmos.webtest.basetools.HolmosAnnotationTool;
import holmos.webtest.basetools.HolmosBaseTools;
import holmos.webtest.exceptions.HolmosFailedError;
import holmos.webtest.junitextentions.annotations.DataBase;
import holmos.webtest.junitextentions.annotations.MultiThread;
import holmos.webtest.junitextentions.annotations.Parameter;
import holmos.webtest.junitextentions.annotations.RunAfter;
import holmos.webtest.junitextentions.annotations.Source;
import holmos.webtest.junitextentions.annotations.Timesout;
import holmos.webtest.junitextentions.parameters.HolmosFrameWorkMethod;
import holmos.webtest.junitextentions.parameters.ParameterDataInfo;
import holmos.webtest.junitextentions.parameters.ParameterFrameWorkMethod;
import holmos.webtest.junitextentions.parameters.database.ConnectionInfo;
import holmos.webtest.junitextentions.parameters.getter.DataGetter;
import holmos.webtest.junitextentions.parameters.getter.DataGetterFactory;
import holmos.webtest.junitextentions.parameters.getter.DatabaseDataGetter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.junit.Test;
import org.junit.runner.Description;
import org.junit.runner.manipulation.Filter;
import org.junit.runner.manipulation.NoTestsRemainException;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.ParentRunner;
import org.junit.runners.model.FrameworkField;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.RunnerScheduler;
import org.junit.runners.model.Statement;
/**
* junit的case扩展顺序执行器
*
* @author 吴银龙([email protected] )
* */
public class HolmosRunner extends ParentRunner{
/*所有待测的测试方法*/
private List children;
/**此测试类中所有的{@link HolmosFrameWorkMethod}类型方法,这种类型将以执行为单位的方法组织起来*/
private ArrayListholmosMethods;
/*类级别的数据库连接信息*/
private HashMapconnections=new HashMap();
/**本测试类所有的测试参数数据读取器*/
private ArrayList parameterDataGetters;
/**设置类所有测试方法的超时时间*/
private int testClassTimesout;
/**测试类实例*/
private Object testTarget;
/*数据源信息缓冲池*/
private HashMapsourceInfo=new HashMap();
public static HashMapsources=new HashMap();
private static Class>testClassforGetter;
public static Class> getTestClassForGetter(){
return testClassforGetter;
}
public HolmosRunner(Class> klass) throws InitializationError {
super(klass);
//检查哪些带有@Source注解或者带有@Parameter注解的方法,如果有不是public类型的,将抛出异常,不予执行
try {getTestTarget();} catch (Exception e) {}
validatePublicModiferWithAnnotation(Source.class);
validatePublicModiferWithAnnotation(Parameter.class);
volidateDeadLockExcuteOrder();
initDataGetters();
initExecuteOrderInfo();
initTestClassTimesout();
}
private void initTestClassTimesout() {
Timesout timesout=HolmosAnnotationTool.getClassLevelAnnotation(getTestClass().getClass(), Timesout.class);
if(timesout!=null){
testClassTimesout=timesout.value();
if(testClassTimesout<=0)testClassTimesout=1;
}else{
testClassTimesout=-1;//知道所有用例执行完毕
}
}
@Override
protected List getChildren() {
return computeTestMethods();
}
@Override
protected Description describeChild(ParameterFrameWorkMethod method) {
Description description= Description.createTestDescription(getTestClass().getJavaClass(),
testName(method), method.getAnnotations());
return description;
}
@Override
protected void runChild(ParameterFrameWorkMethod child, RunNotifier notifier) {
try {
HolmosFrameWorkMethod holmosFrameWorkMethod=getMethodByName(child.getName());
holmosFrameWorkMethod.setTarget(getTestTarget());
holmosFrameWorkMethod.setNotifier(notifier);
if(!holmosFrameWorkMethod.hasPrecursorMethod())
holmosFrameWorkMethod.invokeExplosively(getTestTarget(), notifier);
} catch (Exception e) {
e.printStackTrace();
} catch (Throwable e) {
e.printStackTrace();
}
}
private List fFilteredChildren= null;
private RunnerScheduler fScheduler= new RunnerScheduler() {
public void schedule(Runnable childStatement) {
childStatement.run();
}
public void finished() {
if(HolmosRunner.this.testClassTimesout==-1){
while(true){
if(isAllexecuted())
return;
HolmosBaseTools.sleep(30);
}
}else{
int i=0,milliseconds=1000*testClassTimesout;
while(true){
if(i>=milliseconds){
throw new HolmosFailedError(getTestClass().getName()+"执行超时,设置的超时时间为"+testClassTimesout+"秒!");
}
if(isAllexecuted())
return;
}
}
}
private boolean isAllexecuted(){
for(ParameterFrameWorkMethod method:getFilteredChildren()){
if(!getMethodByName(method.getName()).isExecuted())
return false;
}
return true;
}
};
protected Statement childrenInvoker(final RunNotifier notifier) {
return new Statement() {
@Override
public void evaluate() {
runChildren(notifier);
}
};
}
private boolean shouldRun(Filter filter, ParameterFrameWorkMethod each) {
return filter.shouldRun(describeChild(each));
}
public void filter(Filter filter) throws NoTestsRemainException {
for (Iterator iter = getFilteredChildren().iterator(); iter.hasNext(); ) {
ParameterFrameWorkMethod each = iter.next();
if (shouldRun(filter, each))
try {
filter.apply(each);
} catch (NoTestsRemainException e) {
iter.remove();
}
else
iter.remove();
}
if (getFilteredChildren().isEmpty()) {
throw new NoTestsRemainException();
}
}
private void runChildren(final RunNotifier notifier) {
for (final ParameterFrameWorkMethod each : getFilteredChildren())
fScheduler.schedule(new Runnable() {
public void run() {
HolmosRunner.this.runChild(each, notifier);
}
});
fScheduler.finished();
}
private List getFilteredChildren() {
if (fFilteredChildren == null)
fFilteredChildren = new ArrayList(getChildren());
return fFilteredChildren;
}
protected String testName(FrameworkMethod method) {
if(method instanceof ParameterFrameWorkMethod){
String name = method.toString();
((ParameterFrameWorkMethod) method).setMethodName(null);
return name;
}
return method.getName();
}
/**
* 实例化待测的测试类,此类里面包含了所有带有@Test注解的测试方法,并加上了带有@Source的方法,如果此方法是在测试类级别的注解
* 那么这个时候便会查看ID变量如果没有的话并且有参数信息,那么参数将会被按成默认值处理(对象为null,数值为0/0.0)
* */
protected Object getTestTarget() throws Exception {
//实例化测试类,生成测试对象
if(null==testTarget)
testTarget = getTestClass().getOnlyConstructor().newInstance();
HolmosRunner.testClassforGetter=HolmosRunner.this.testTarget.getClass();
return testTarget;
}
/**
* 初始化执行顺序前驱和后继信息以及确立执行顺序
* 带有多线程异步执行注解{@link MultiThread}的放到最前面
* */
private void initExecuteOrderInfo() {
if(null==holmosMethods)
computeTestMethods();
for(HolmosFrameWorkMethod method:holmosMethods){
RunAfter runAfter=method.getMethod().getAnnotation(RunAfter.class);
if(runAfter!=null){
HolmosFrameWorkMethod precursorMethod=getMethodByName(runAfter.methodName());
if(precursorMethod!=null)
precursorMethod.addSuccessorMethods(method);
else
throw new HolmosFailedError("方法"+method.getMethod().getName()+"的@RunAfter注解里面的方法名字在此测试类里面不存在,请您检查!");
}
}
}
private HolmosFrameWorkMethod getMethodByName(String methodName){
for(HolmosFrameWorkMethod method:getHolmosMethods()){
if(method.getMethod().getName().equalsIgnoreCase(methodName))
return method;
}return null;
}
/**
* 得到此testClass里面所有的测试方法,以执行为单位
* */
protected List computeTestMethods() {
if(null==children){
//children只会获取一次,获取一次之后就会缓存在这里面
children=new ArrayList();
holmosMethods=new ArrayList();
//得到所有的测试方法
for(FrameworkMethod method:getTestClass().getAnnotatedMethods(Test.class)){
wrapperMethod(method);
}
}
return children;
}
/**
* 获取HolmosFrameWorkMethod列表,以组织为单位
* */
private ArrayListgetHolmosMethods(){
if(null==holmosMethods){
computeTestMethods();
}return holmosMethods;
}
/**装配方法*/
private void wrapperMethod(FrameworkMethod method){
HolmosFrameWorkMethod holmosMethod=new HolmosFrameWorkMethod(method);
if(holmosMethod.isMultiThread()){
holmosMethods.add(0, holmosMethod);
children.addAll(0, holmosMethod.getExcuteFrameWorkMethods());
}else{
holmosMethods.add(holmosMethod);
children.addAll(holmosMethod.getExcuteFrameWorkMethods());
}
wrapperDataGetter(holmosMethod);
}
private void wrapperDataGetter(HolmosFrameWorkMethod method){
Source source=method.getMethod().getAnnotation(Source.class);
if(source!=null){
method.setGetter(sources.get(source.sourceID()));
}
}
/**
* 初始化参数数据源配置信息,在类和方法的@Source注解里面指定
* */
private void initDataGetters() {
parameterDataGetters=new ArrayList();
initDataBaseConnections();
for(Source source:getSourceAnnotations()){
volidateValueOfSourceAnnotation(source);
String mark=getValueOfSourceAnnotation(source);
if(sourceInfo.get(mark)!=null)
throw new HolmosFailedError("配置了相同的数据源信息:"+mark);
DataGetter getter=DataGetterFactory.getDataGetter(source);
if((!source.selector().equalsIgnoreCase(""))&&(source.selector()!=null)){
if(connections.get(source.connectionName())==null)
throw new HolmosFailedError(source.connectionName()+"没有为数据源配置数据库连接!");
((DatabaseDataGetter)getter).setConnection(connections.get(source.connectionName()));
}
ParameterDataInfo parameterDataInfo=new ParameterDataInfo(getter);
parameterDataGetters.add(parameterDataInfo);
sourceInfo.put(mark, parameterDataInfo);
if(sources.get(source.sourceID())!=null)
throw new HolmosFailedError("不同的参数源信息的id配置重复!请查看,重复的id为:"+source.sourceID());
sources.put(source.sourceID(), sourceInfo.get(mark));
}
}
/**
* 检查在配置case执行顺序的时候,是否出现了死锁现象,比如1->2->3->1这个时候就出现了死锁,如果出现了死锁,将会抛出异常
* */
private void volidateDeadLockExcuteOrder() {
volidateRunAfterAnnotationMethodName();
Listmethods=getTestClass().getAnnotatedMethods(RunAfter.class);
HashMap>orderInfo=new HashMap>();
ArrayListafterMethods=new ArrayList();
for(FrameworkMethod method:methods){
String priorMethodName=method.getAnnotation(RunAfter.class).methodName();
if(orderInfo.get(priorMethodName)==null)
afterMethods=new ArrayList();
else
afterMethods=orderInfo.get(priorMethodName);
afterMethods.add(method.getName());
orderInfo.put(priorMethodName, afterMethods);
}
volidateDeadLock(orderInfo);
}
@SuppressWarnings("unchecked")
private void volidateDeadLock(HashMap> orderInfo) {
Iterator>>iterator=orderInfo.entrySet().iterator();
while(iterator.hasNext()){
@SuppressWarnings("rawtypes")
Map.Entry entry = (Map.Entry) iterator.next();
for(String next:(ArrayList)entry.getValue()){
String deadLockPath=getDeadLockPath((String) entry.getKey(),next,orderInfo);
if(deadLockPath!=null){
throw new HolmosFailedError("方法"+entry.getKey()+"()和方法"+next+"()存在了运行顺序死锁,死锁" +
"情况如下:\n"+deadLockPath);
}
}
}
}
private String getDeadLockPath(String start, String end,
HashMap> orderInfo) {
if(start.equalsIgnoreCase(end))return start+"->"+start+"->"+start;
String startToEnd=getReachablePath(start,end,orderInfo);
String endToStart=getReachablePath(end,start,orderInfo);
if(startToEnd!=null&&endToStart!=null){
return startToEnd+endToStart.substring(endToStart.indexOf('-'));
}
return null;
}
private String getReachablePath(String start, String end,
HashMap> orderInfo) {
if(start.equalsIgnoreCase(end))return start;
ArrayListnodes=orderInfo.get(start);
if(null==nodes)return null;
for(String node:nodes){
String pathTemp=getReachablePath(node, end, orderInfo);
if(null!=pathTemp)
return start+"->"+pathTemp;
}
return null;
}
/**
* 校验在{@link RunAfter}注解里面的方法名称必须是此测试类中的方法
* */
private void volidateRunAfterAnnotationMethodName() {
Listmethods=getTestClass().getAnnotatedMethods(RunAfter.class);
for(FrameworkMethod method:methods){
volidateMethodInTestClass(method);
}
}
private void volidateMethodInTestClass(FrameworkMethod method){
ListallTestMethods=getTestClass().getAnnotatedMethods(Test.class);
for(FrameworkMethod methodTemp:allTestMethods){
if(methodTemp.getName().equalsIgnoreCase(method.getName()))
return;
}
throw new HolmosFailedError(method.getName()+"方法里面的@RunAfer注解里面的方法名字不在此测试类测试方法列表里面!");
}
private String getValueOfSourceAnnotation(Source source){
if(source.file()==""||source.file().equalsIgnoreCase(""))
return source.selector();
return source.file();
}
/**
* 校验该测试类的所有的Source注解的数据源信息是否符合要求
* 不能都有值
* 不能是都为null或空窜
* */
private void volidateValueOfSourceAnnotation(Source source){
int sourceCount=0;
if(source.file()!=null&&!source.file().equalsIgnoreCase(""))
sourceCount++;
if(source.selector()!=null&&!source.selector().equalsIgnoreCase(""))
sourceCount++;
if(source.className()!=null&&!source.className().equalsIgnoreCase(""))
sourceCount++;
if(sourceCount>=2){
throw new HolmosFailedError("在一个数据源配置里面不能同时配置数据库和文件两种类型!");
}if(0==sourceCount){
throw new HolmosFailedError("@Source没有配置数据源!");
}if(source.sourceID()<=0)
throw new HolmosFailedError("Holmos框架不允许参数源的id值小于等于0!请设置参数源的id值为一个正数!");
}
/**
* 获取此测试类中的所有的@Source注解对象;如果有类级别的注解,那么第一个就是这个类级别的,方法级别的按照定义的顺序依次排列
*
* */
private ArrayList getSourceAnnotations(){
ArrayListsources=new ArrayList();
try {
Source sourceOfClass=HolmosAnnotationTool.getClassLevelAnnotation(getTestTarget().getClass(), Source.class);
if(null!=sourceOfClass)
sources.add(sourceOfClass);
sources.addAll(HolmosAnnotationTool.getMethodLevelAnnotations(getTestTarget().getClass(), Source.class));
} catch (Exception e) {
e.printStackTrace();
}
return sources;
}
/**
* 初始化类级别的数据库连接信息,在@Database注解里面指定,必须制定数据库连接的名字,如果不指定,抛出异常
* */
private void initDataBaseConnections() {
try{
DataBase databaseOfClass=HolmosAnnotationTool.getClassLevelAnnotation(getTestTarget().getClass(), DataBase.class);
if(databaseOfClass!=null){
connections.put(databaseOfClass.connectionName(),new ConnectionInfo(databaseOfClass));
}for(DataBase database:HolmosAnnotationTool.getMethodLevelAnnotations(getTestTarget().getClass(), DataBase.class)){
if(connections.get(database.connectionName())!=null)
throw new HolmosFailedError("数据库连接的名字重复了,这个重复的名字为:"+database.connectionName());
connections.put(database.connectionName(),new ConnectionInfo(database));
}
}catch(Exception e){}
}
private void validatePublicModiferWithAnnotation(Class extends Annotation> annotation){
Listfields=getTestClass().getAnnotatedFields(annotation);
for(FrameworkField field:fields){
if((Modifier.PUBLIC & field.getField().getModifiers())==0){
throw new HolmosFailedError(field.getName()+"的修饰符不是public类型,程序已经退出!Holmos框架不允许不是public类型的测试方法运行!");
}
}
}
}