2024年最全对自动化测试的一些展望与理解_自动化测试总结与展望,阿里珍藏版软件测试框架体系架构手写文档

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上软件测试知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化的资料的朋友,可以戳这里获取

3.2.1 环境搭建

环境搭建时,主要用了以下工具:

  • Git:管理代码工程
  • TestNG:作为测试框架
  • Maven:管理依赖包
  • Log4j:管理日志
  • Hibernate:实现数据库交互
  • HttpClient:实现请求发送

之所以没有用MyBatis,觉得相对来说,MyBatis是一个半ORM的框架,它需要自己额外维护一份sql映射文件,而Hibernate是全ORM的,可以省去这一步。对于JDBC的方式,当然它也可以访问数据库,只不过相对来说,使用ORM框架可以更贴近面向对象的编程方式。

3.2.2 不同集群配置管理

在实现过程中,因为不同的集群会有不同的配置,比如webserver host、登陆后台webserver的用户名/密码、公共账号信息、数据库信息等等。为了让一份代码可以在不同集群去共用,就必须把这些配置信息从代码中剥离出来。可以用配置文件的形式来统一管理集群的配置信息,如图所示:

配置文件管理

每个文件代表一个集群的配置。在代码中可以通过java.util.Properties类读取配置文件的方式载入各项配置信息:

/**
 * 根据指定的配置文件名,初始化配置
 * @param configFile
 * @throws IOException
 */
public PropertiesUtil(String configFile) throws IOException{
	this.configFile =DEFAUL_CONFIG_FILE_DIRECTORY + configFile;
    InputStream fis = new FileInputStream(this.configFile);
    props = new Properties();
    props.load(fis);
    //关闭资源
    fis.close();
}

/**
 * 根据key值读取配置的值
 * @param key key值
 * @return key 键对应的值 
 * @throws IOException 
 */
public String readValue(String key){
    return  props.getProperty(key);
}

/**
 * 读取properties的全部信息
 * @throws FileNotFoundException 配置文件没有找到
 * @throws IOException 关闭资源文件,或者加载配置文件错误
 * 
 */
public Map<String,String> readAllProperties(){
    //保存所有的键值
    Map<String,String> map=new HashMap<String,String>();
    Enumeration<?> en = props.propertyNames();
    while (en.hasMoreElements()) {
        String key = (String) en.nextElement();
        String property = props.getProperty(key);
        map.put(key, property);
    }
    return map;
}

到这里,解决了配置读取的问题,还需要解决代码运行时如何让它自己去选择正确的集群配置文件的问题。我是将选择配置文件的逻辑全部封装到了一个工厂类BaseConfigFactory.java中,在实际测试使用时,我只需要通过工厂类的静态方法BaseConfigFactory.getInstance()去获取想要的配置信息,而不需要关心它到底是如何去选择正确的配置文件的。工厂类的实现可以参考:

public class BaseConfigFactory {
	private static final String testEnv= System.getenv("TEST_ENV") == null ? "null" : System.getenv("TEST_ENV");
	private static Logger logger = Logger.getLogger(BaseConfigFactory.class);
	private static BaseConfig baseConfig;
	private static HashMap<String, String> clusterConfigMap;
	public static synchronized BaseConfig getInstance(){
		if (null == baseConfig){
			PropertyConfigurator.configure("log4j.properties");
			initMap();
			setupConfig();
		}
		return baseConfig;
	}
	
	
	public static void initMap(){
		clusterConfigMap = new HashMap<>();
		clusterConfigMap.put("TEST-BJ", "test-bj.properties");
		clusterConfigMap.put("ONLINE-BJ", "online-bj.properties");
		clusterConfigMap.put("ONLINE-XS", "online-xs.properties");
		clusterConfigMap.put("ONLINE-LT", "online-lt.properties");
		clusterConfigMap.put("ONLINE-BEIJING", "online-beijing.properties");
		clusterConfigMap.put("ONLINE-HD", "online-hd.properties");
		clusterConfigMap.put("null", "test-local.properties");
	}
	
	public static void setupConfig(){
		logger.info("TEST ENV: " + testEnv);
		String propertyFile = clusterConfigMap.get(testEnv);
		logger.info("Using '" + propertyFile + "' as property file.");
		baseConfig = new BaseConfig(propertyFile);		
	}

}

即,将所有的集群的配置放入到一个Map中,然后通过读取环境变量TEST_ENV的值来选取具体的集群配置文件clusterConfigMap.get(testEnv)。

3.2.3 log4j日志管理

良好的日志输出是帮助定位问题的关键环节,尤其是定位服务器上执行时出现的问题。这边贴一个log4j的配置:

### set log levels ###
log4j.rootLogger = debug, stdout, D, E

### 输出到控制台 ###
log4j.appender.stdout = org.apache.log4j.ConsoleAppender 
log4j.appender.stdout.Target = System.out
log4j.appender.stdout.layout = org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss.SSS Z} %p [%c{1}] [Thread-%t] %m%n

### 输出到日志文件 ###
log4j.appender.D = org.apache.log4j.DailyRollingFileAppender
log4j.appender.D.File = logs/console.log
log4j.appender.D.Append = true
##输出Debug级别以上的日志##
log4j.appender.D.Threshold = INFO  
log4j.appender.D.layout = org.apache.log4j.PatternLayout
log4j.appender.D.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss.SSS Z} %p [%c{1}] [Thread-%t] %m%n

### 保存异常信息到单独文件 ###
log4j.appender.E = org.apache.log4j.DailyRollingFileAppender
##异常日志文件名##
log4j.appender.E.File = logs/error.log
log4j.appender.E.Append = true
##只输出ERROR级别以上的日志##
log4j.appender.E.Threshold = ERROR
log4j.appender.E.layout = org.apache.log4j.PatternLayout
log4j.appender.E.layout.ConversionPattern=%d{yyyy/MM/dd HH:mm:ss.SSS Z} %p [%c{1}] [Thread-%t] %m%n

##Hibernate日志级别设置
log4j.logger.org.hibernate.ps.PreparedStatementCache=WARN
log4j.logger.org.hibernate=ERROR

# Changing the log level to DEBUG will result in Hibernate generated
# SQL to be logged.
log4j.logger.org.hibernate.SQL=ERROR

# Changing the log level to DEBUG will result in the PreparedStatement
# bound variable values to be logged.
log4j.logger.org.hibernate.type=ERROR

该配置将INFO级别和ERROR级别的日志分别定位输出到不同的文件,且日志文件会按照日期进行自动归档,输出的格式包含了日志的日期、级别、类信息、线程信息、日志内容等。

一般情况下,对于接口测试,当接口测试用例失败时,我们要打印的日志包括:请求的url、参数、方法、实际响应、期望响应等等。

3.3 分层设计、解耦

首先看一下项目的工程目录:

项目工程目录

可以看到,项目中包含了多个package,各个package的作用已经在图片中标示了。以前好多测试人员的习惯是将api代码的调用、测试方法的编写、data Provider的编写、测试数据的构造全部写在一个类文件中,这样做其实会有几个问题:

  • 可读性差
  • 代码复用性低
  • 维护性差
  • 难以调试
  • 耦合带来的其它各类问题

此外,如果不同集群的测试数据不同,会有大量的if判断,结果是灾难性的。

下面以一个用例为例,展示代码的结构:

测试api:

public class ScheduleApi extends BaseAzkabanApi{
    ...
    ...
    /**
     * 使用默认公共账号、email、失败策略、sla报警邮箱新增正常调度。
     * @param projectName
     * @param flow
     * @param projectId
     * @param scheduleTime
     * @param scheduleDate
     * @param period
     * @return
     */
    public ResponseCode addNormSched(String projectName, String flow, String projectId, String scheduleTime, String scheduleDate,String period){
    	return scheduleFlow(projectName, flow, projectId, scheduleTime, scheduleDate, defaultProxyUser, defaultProxyEmail, period,  defaultSlaEmail);
    }
    ...
    ...
}

测试代码test:

@Test(singleThreaded=true)
public class ScheduleTest{
    ...
    ...
    /**
     * 新增正常调度
     * @param projectName
     * @param flow
     */
    @Test(priority=1, dataProvider="addNormSched", dataProviderClass=ScheduleDataProvider.class, testName="1410356")
    public void addNormSched(String projectName, String flow, String expectedStatus, String hasScheduleId, String message){
    	ResponseCode rc= scheduleApi.addNormSched(projectName, flow);
    	Assert.assertEquals(rc.getStatus(), expectedStatus, message+rc.getDebugInfo("返回结果中的状态status对应值"));
    	Assert.assertEquals(rc.hasProperty("scheduleId"), Boolean.parseBoolean(hasScheduleId), message+rc.getDebugInfo("返回结果中是否包含scheduleId"));
    }
    ...
    ...
}

测试用例dataProvider:

public class ScheduleDataProvider {
	@DataProvider(name = "addNormSched", parallel=true)
	public static Object [][] addNormSched(){
		return new Object[][]{
			ScheduleTestData.validNormSchedule,
			ScheduleTestData.notExistedProject,
			ScheduleTestData.notExistedFlow
		};
	}
	...
	...
}

测试数据testdata:

public class ScheduleTestData extends BaseTestData{	
	...
	...	
	//Testdata for addNormSched
	public static Object[] validNormSchedule={VALID_PROJECT_NAME, VALID_NORMAL_SCHEDULE_FLOW, "success", "true", "设置有效的正常调度"};
	public static Object[] notExistedProject={NOT_EXIST_PROJECT_NAME, VALID_NORMAL_SCHEDULE_FLOW, "error", "false", "不存在的project"};
	public static Object[] notExistedFlow={VALID_PROJECT_NAME, NOT_EXIST_FLOW_NAME, "error", "fasle", "不存在的flow"};
	...
	...
}

可以看到,用例的测试代码test类是非常简洁的,只要调用api类封装的接口,然后进行assert判断即可。

关于测试数据,将dataprovider与testdata进行分离,也是为了后续可能会灵活地调整下架用例,只需要去除dataprovider类中的用例行即可,而testdata中的数据仍然可以留着复用。

另外,前面提到了不同集群测试数据的管理。再介绍下我这边的实现方式:

  • 不同测试类使用的公共数据,存放于BaseTestData基类中,让其它testdata类继承于基类
  • 不同集群可以共用的数据,尽量共用,以常量的方式存储于testdata类中
  • 不同集群无法共用的数据,统一存放于特定的json文件管理

关于json文件管理数据,其实跟配置文件的管理类似,如下图所示:

json数据目录

History.json:

{			
	"validTotalFetch":{
		"key":"",
		"beginTime":"2017-06-30%2015:30",
		"endTime":"2017-06-30%2015:50",
		"expectedTotal":"7"
	},
	
	"validImmediatelyFetch":{
		"key":"instant_execute_job",
		"beginTime":"2017-06-30%2013:30",
		"endTime":"2017-06-30%2013:40",
		"expectedTotal":"1"
	},
	
	"validScheduledFetch":{
		"key":"online_schedule_job",
		"beginTime":"2017-06-30%2014:30",
		"endTime":"2017-06-30%2014:40",
		"expectedTotal":"2"
	}
}

3.4 改进与提升

在自动化的实施过程中,还遇到了一些问题可能对其它项目也会有一定的借鉴意义。这边罗列下几个我觉得比较有意思的问题。

3.4.1 webserver高可用的支持

我们的后台webserver是支持高可用的,所以每次运维上线后webserver的host可能会发生变化,以及在服务运行过程中也可能会发生webserver切换。如果每次去手动调整自动化用例的配置信息,是一件非常麻烦的事情。

解决的方式就是在配置文件中,将主从webserver的host都填写进去,在测试过程中,如果发生请求失败,则允许切换一次host。

img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

在测试过程中,如果发生请求失败,则允许切换一次host。

[外链图片转存中…(img-O2vjK1tf-1715130243250)]
[外链图片转存中…(img-n0Oa4NrK-1715130243251)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 19
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip
电气工程自动化是一个不断发展和创新的领域,其前沿包括以下几个方面: 1. 人工智能(AI)与自动化:人工智能技术可以应用于电气自动化领域中,如机器学习、深度学习和神经网络等算法可用于优化电气系统的控制和监测,提高电气系统的效率和可靠性。 2. 智能电网:智能电网是电力系统的一种新型变革,它将传统的单向供电网络转变为双向交互网络,通过数字化技术、通信技术和自适应技术,实现了对电力的智能化、自适应化和可持续化。 3. 电动汽车:随着全球环保意识的提高,电动汽车已成为未来的趋势,电气工程自动化领域在电动汽车的研究和发展方面也有很大的作用,如电动汽车的充电设备、电池管理系统等。 4. 能源储存技术:能源储存技术是实现可持续能源利用的重要手段,电气工程自动化领域在能源储存技术的研究和应用方面也有很大的潜力,如大规模的储能系统、电动汽车电池等。 5. 工业4.0:工业4.0是新一代工业革命的代表,它将制造业数字化、网络化、智能化和自适应化,实现了工业生产的高度自动化和智能化,电气工程自动化领域也是工业4.0的重要支撑。 总之,电气工程自动化领域的前沿不断拓展,未来将会出现更多的新技术和新应用,这需要电气工程自动化专业人才不断地创新和发展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值