热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

利用反射简单模拟Spring的控制反转(Ioc)和依赖注入(DI)

1.配置文件(.properties)中配置要扫描的包:#扫描page对象的包init.pageobj.Packageec.qa.autotest.ui.admin.porta


1.配置文件(.properties)中配置要扫描的包:

#扫描page对象的包
init.pageobj.Package = ec.qa.autotest.ui.admin.portal.pageobject,ec.qa.autotest.ui.common.action,ec.qa.autotest.ui.supplier.portal.pageobject


2.代码实现:

自定义2个标签:

@PageObject   @AutoInject:

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;


/**
* @author xin.wang
* @see 标识当前类是否是页面对象
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PageObject {
boolean lazyLoad() default false;
}
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;/** * @author xin.wang * 自动装配标签 */@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface AutoInject {	boolean enable() default true;}

package ec.qa.autotest.ui.utility;

import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import ec.qa.autotest.ui.custom.annotation.AutoInject;
import ec.qa.autotest.ui.custom.annotation.PageObject;
import ec.qa.autotest.ui.testbase.TestBase;

/**
* @author xin.wang
* 1.模拟IOC容器 通过反射扫描配置好的pageobject包并将 pageobject实例存放到全局静态MAP中。
* 2.实现了依赖注入功能 DI
*/

public class initPageObject {

private static Field[] fields = null;
	private  Object pageobj;
	private String packAgePref = "src\\main\\java\\";			public initPageObject(Object ob) {		this.pageobj = ob;		PageObjectUtil.setPageObjMap(initPageObjMap()); //将页面对象存放到MAP中,MAP充当一个bean容器	}	private HashMap initPageObjMap() {		HashMap pageobjs = new HashMap();		HashSet fieldSet = new HashSet();		String curClassName = TestBase.getTestCaseDeclaringClass();		try {			String[] packagePath = PropertiesUtil.getProValue("init.pageobj.Package").split(",");			fields = Class.forName(curClassName).getDeclaredFields();			fillFieldNameSet(fields, fieldSet);			for (String pp : packagePath) {				ArrayList classNames = new ArrayList();				getClassName(packAgePref + pp.replace(".", "\\"), classNames, pp);				for (String className : classNames) {					Class classObj = Class.forName(className);					if (classObj.getAnnotation(PageObject.class) != null							&& fieldSet.contains(classObj.getSimpleName())) {						pageobjs.put(classObj.getSimpleName(), classObj.newInstance());					}				}			}			injectPageObj(fields, pageobjs);		} catch (Exception e) {			e.printStackTrace();		}		return pageobjs;	}/** * @author xin.wang * @param fields * @param pageobjs * @throws IllegalArgumentException * @throws IllegalAccessException *实现向测试用例类自动注入页面对象的功能 */	private void injectPageObj(Field[] fields, HashMap pageobjs)			throws IllegalArgumentException, IllegalAccessException {		for (Field f : fields) {			f.setAccessible(true);			f.set(pageobj, pageobjs.get(f.getType().getSimpleName()));			f.setAccessible(false);		}	}	private void fillFieldNameSet(Field[] fields, HashSet fieldSet) {		for (Field f : fields) {			if (f.getAnnotation(AutoInject.class) != null) {				fieldSet.add(f.getType().getSimpleName());			}		}	}	private ArrayList getClassName(String folderPath, ArrayList className, String packageName)			throws Exception {		File files = new File(folderPath);		for (File f : files.listFiles()) {			if (f.isFile() && f.getName().endsWith(".java")) {				className.add(packageName + "." + f.getName().substring(0, f.getName().indexOf(".")));			}		}		return null;	}}

3.如何使用上面的功能:由于测试用例的运行调度使用的是testng所以需要几个testng的机制来使用,在testng实例化当前测试用例所在类的时候进行注入:

示例:

@BeforeMethod

public void initTestCase(){

new initPageObject(this);  //将当前对象传给注入功能类 对此实例中标有@AutoInject的类成员进行注入

}

实例:

public void configDriver(ConfigDriverParameters cp) throws Exception {
testCaseDeclaringClass = cp.getTestMethod().getDeclaringClass().getName();
String website = cp.getTargetWebSite();
if (!success) {
System.out.println("\n=======测试用例准备重试=======");
reTryCount++;
success = true;
}
System.out.println("\n======测试用例: " + cp.getTestMethod().getName() + " 开始执行======" + "\n===测试用例运行的浏览器类型:"
+ browserType + " ===" + "\n测试网站地址: " + website);
webDriver = DriverUtil.getWebDriver(browserType);
new initPageObject(this); //关键点在此 其他忽略
webDriver.manage().timeouts().implicitlyWait(cp.getSerachElementTime(), TimeUnit.SECONDS);
webDriver.manage().window().maximize();
webDriver.manage().timeouts().pageLoadTimeout(cp.getPageLoadTime(), TimeUnit.SECONDS);
if (COOKIEsUtil.getCk() != null) {
webDriver.manage().timeouts().pageLoadTimeout(3, TimeUnit.SECONDS);
try {
webDriver.get(website);
} catch (Exception e) {
}
webDriver.manage().addCOOKIE(COOKIEsUtil.getCk());
}
try {
webDriver.get(website);
} catch (Exception e) {
}
webDriver.manage().timeouts().pageLoadTimeout(-1, TimeUnit.SECONDS);
}


测试页面对象类实例:

package ec.qa.autotest.ui.admin.portal.pageobject;

import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.How;
import org.openqa.selenium.support.PageFactory;
import ec.qa.autotest.ui.custom.annotation.PageObject;
import ec.qa.autotest.ui.testbase.TestBase;

/**
* @author xin.wang
* @see 登录页面
*/
@PageObject
public class AdminPortalLoginPage {

@FindBy(how = How.ID, using = "loginname")
private WebElement userNameInputBox;

@FindBy(how = How.ID, using = "password")
private WebElement passwordInputBox;

@FindBy(how = How.NAME, using = "loginForm")
private WebElement submitButton;

public void setUserNameContent(String username) {
userNameInputBox.click();
userNameInputBox.sendKeys(username);
}

public void setPwdContent(String pwd) {
passwordInputBox.click();
passwordInputBox.sendKeys(pwd);
}

public void getUserNameContent(String username) {
userNameInputBox.getText();
}

public String getUserNameContent() {
return userNameInputBox.getText();
}

public AdminPortalLoginPage(){
PageFactory.initElements(TestBase.getWebDriver(), this);
}

/**
* @author xin.wang
* @see 登录后台管理系统
*/

public void loginAdminPortal(String username, String pwd) {
setUserNameContent(username);
setPwdContent(pwd);
submitButton.submit();
}
}

测试用例类实例:

package ec.qa.autotest.ui.admin.portal.testcases;

import org.testng.AssertJUnit;
import org.testng.annotations.Test;
import ec.qa.autotest.ui.admin.portal.pageobject.AdminPortalLoginPage;
import ec.qa.autotest.ui.admin.portal.pageobject.NavigationMenu;
import ec.qa.autotest.ui.custom.annotation.AutoInject;
import ec.qa.autotest.ui.testbase.AdminPortalTestBase;

/**
*
* @auther xin.wang
*登录后台管理系统
*/
public class LoginAdminPortal extends AdminPortalTestBase{

@AutoInject
private AdminPortalLoginPage ecHomePage;

@AutoInject
private NavigationMenu ctPage;

@Test
public void loginAdminPortal() throws Exception{
ecHomePage.loginAdminPortal("admin", "111111");
AssertJUnit.assertEquals(ctPage.getWelcomeContent(), "欢迎您,");
AssertJUnit.assertEquals(ctPage.getCurLoginUser(), "超级管理员");
ctPage.goToProdcutLibPage();
}
}

4.既然实现了IOC容器,那么我在必要情况下可以手动拿到当前测试需要的页面类对象:在 initPageObject 类中 标红部分既是向容器中注入页面对象实例的过程,通过调用如下代码 在测试用例中可随意拿出页面对象进行操作:

package ec.qa.autotest.ui.utility;

import java.util.HashMap;

/**
* @author xin.wang
* 获取页面对象的工具类
*/
public class PageObjectUtil {

private static HashMap pageobjs = null;

public static void setPageObjMap(HashMap Map){
pageobjs = Map;
}

@SuppressWarnings("unchecked")
public static T getPageObject(String pageObjectClassName){
return (T)pageobjs.get(pageObjectClassName);
}

}

用例中调用 PageObjectUtil .getPageObject("pageobjectclassname") 即可.

public class LoginAdminPortal extends AdminPortalTestBase{

@AutoInject
private NavigationMenu ctPage;

@Test(invocatiOnCount= 1)
public void loginAdminPortal() throws Exception{
AssertJUnit.assertEquals("欢迎您,",ctPage.getWelcomeContent());
AssertJUnit.assertEquals("超级管理员1",ctPage.getCurLoginUser());
ctPage.goToProdcutLibPage();

ctPage =PageObjectUtil.getPageObject("NavigationMenu");
ctPage.clickProdcutCenterMenu();
}
}




推荐阅读
  • Java如何导入和导出Excel文件的方法和步骤详解
    本文详细介绍了在SpringBoot中使用Java导入和导出Excel文件的方法和步骤,包括添加操作Excel的依赖、自定义注解等。文章还提供了示例代码,并将代码上传至GitHub供访问。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 标题: ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • 面向对象之3:封装的总结及实现方法
    本文总结了面向对象中封装的概念和好处,以及在Java中如何实现封装。封装是将过程和数据用一个外壳隐藏起来,只能通过提供的接口进行访问。适当的封装可以提高程序的理解性和维护性,增强程序的安全性。在Java中,封装可以通过将属性私有化并使用权限修饰符来实现,同时可以通过方法来访问属性并加入限制条件。 ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • 本文介绍了RxJava在Android开发中的广泛应用以及其在事件总线(Event Bus)实现中的使用方法。RxJava是一种基于观察者模式的异步java库,可以提高开发效率、降低维护成本。通过RxJava,开发者可以实现事件的异步处理和链式操作。对于已经具备RxJava基础的开发者来说,本文将详细介绍如何利用RxJava实现事件总线,并提供了使用建议。 ... [详细]
author-avatar
楼外蔷薇花开
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有