QA转型之在公司快速接手开发前端工程「0经验开发前端2坤月」
前言
测试,最为重要的就是质量和效率。谈到提效,就少不了测试工具、测试平台的开发。来到公司一年半的时候,因为公司业务的变更,我被调去了效能工程组,负责内部几个自动化平台的维护和开发工作。在此之前,对于前端我也仅仅是会一些 HTML/CSS/JavaScript基础语法,并没有太多实际项目工程的开发经验。于是,我走上了一条为期2坤月的前端开发之路 🧑💻
遂,将此五个月的0基础开发并且如何边学习的经验做一次总结,各位大佬如有疑问或沟通,欢迎随时私信。
第一步:了解项目技术栈
我们拿到项目的时候,首先确认下他是使用了什么技术和框架。如,我接手的几个项目技术栈情况如下:
- React(使用React Hook语法)
- Vue2(内部一个老测试工具平台在使用)
- ES6(使用解构赋值、扩展运算符、箭头函数等)
- umi3(前端路由+插件)
- dva(数据层,相当于redux + redux-saga)
- antd(UI组件库)
- Bizcharts: 图表库(会考虑借鉴antD pro封装的图表组件)
推荐开发者工具:
- VSCode(代码编辑器)
- node环境
- npm(包管理工具)
- React Developer Tools(Chroma浏览器插件)
- redux Devtools(Chroma浏览器插件)
vscode插件推荐:
- eslint ,静态代码检查
- gitlens, 查看git 记录
- Bracket Pair Colorizer 彩虹括号
- Indent Rainbow 彩虹缩进
- Prettier - Code formatter, 设置上Format On Save
- Simple React Snippets和ES7+ React/Redux/React-Native snippets, 代码块,快捷键带出大量代码
- @popular 查找使用最多的插件
第二步:工程本地启动
在工程首页的README.md
(仔细阅读)中,一般会介绍该工程的启动方式和注意事项。如
安装依赖:npm install
本地启动:npm start # localhost:9500
查看该项目工程的目录结构,大体要知道每个文件夹、每个文件是做什么用的。例如:
├── README.md
├── base // !不要修改,脚手架自动生成,
├── config // 配置文件夹
│ ├── theme // 主题文件
│ ├── menu // 菜单文件
│ │ ├── menus.json // 用户菜单配置
│ │ └── menu.config.js // !不要修改
│ ├── config.js // umi全局配置
│ ├── config.local.js // umi本地配置
│ ├── config.prod.js // umi生成环境配置
│ └── config.common.js // 用户配置
├── package-lock.json
├── package.json
├── src
│ ├── app.js
│ ├── assets // 图片等静态资源
│ ├── components // 通用组件
│ ├── global.less // 全局样式文件
│ ├── layouts // 整体布局相关(可以在这里做动态菜单)
│ ├── utils // 通用工具
│ └── pages // <--- 用户编写页面的地方
│ └── demo-page // <--- 页面A
│ ├── service // <--- 页面A的service
│ ├── models // <--- 页面A的models
│ ├── components // <--- 页面A相关组件
│ ├── index.jsx // <--- 页面A的主文件
第三步:菜单/路由/本地代理
一般会有一个地方可以配置菜单。如在config/menu文件夹下的文件menus.json
。这里就是我们展示在首页的菜单选项。
{
"path": "auto",
"name": "UI自动化",
"icon": "TrophyOutlined",
"children": [
{ "path": "case", "name": "用例", "icon": "BoxPlotOutlined" },
{ "path": "execSet", "name": "执行集", "icon": "MenuOutlined" },
{ "path": "report", "name": "测试报告", "icon": "PieChartOutlined" }
]
}
找到路由相关文件,如routes.js
,在这里我们可以将路径和组件关联起来。现在用的是配置式路由,根据path匹配显示的组件,如果没有匹配上就显示404。注意最后一行是配置404页面的,当路径和前面所有的配置路径匹配都不成功时,则匹配404页面。
module.exports = [
{
path: '/',
component: '../layouts/index',
routes: [
{ path: '/', redirect: '/auto/execSet/list' },
{ path: '/auto', redirect: '/auto/execSet/list' },
{ path: '/auto/execSet', redirect: '/auto/execSet/list' },
{ path: '/auto/execSet/list', component: '../pages/auto/execSet/list/index' },
{ path: '/auto/case', redirect: '/auto/case/list' },
.....
{ component: '../pages/404' }
],
},
];
找到proxy代理文件,如config.local.js
,在这里我们可以配置接口请求代理地址。在这里切换target可以切换到本地服务端工程地址。
export default {
proxy: {
'/api/testCase': {
// target: 'http://10.221.xx.xxx:xxxx',
target: 'http://xxxx.qa.xxx.com',
secure: false,
changeOrigin: true
},
....
},
};
第四步:项目结构/数据流转
首先我们来看下dva的数据流转:
首先我们根据url访问相关的Route-Component,在组件中我们通过dispatch发送action到model里面的effect或者直接Reducer。
当我们将action发送给Effect,基本上是取服务器上面请求数据的,服务器返回数据之后,effect会发送相应的action给reducer,由唯一能改变state的reducer改变state,然后通过connect重新渲染组件。
当我们将action发送给reducer,那直接由reducer改变state,然后通过connect重新渲染组件。
简单点来说就是: 在subscription方法中我们监听页面路由变化,在effect中去调接口拿数据,在reducer中将返回的数据放到state。
service:
import Fetch from '@/utils/fetch';
const RpcBase = '/api/rpc';
/**
* 获取RPC信息列表
*/
export function getRpcsList({
produceId,
searchWord,
page
}) {
const path = `${RpcBase}/queryRpcList`;
return Fetch.postJson(
path,
{
produceId,
searchWord,
page
}
);
}
...
models:
import * as service from '@/service/rpc';
export default {
namespace: 'rpc',
state: {
// RPC列表
rpcsList: { // data
rpcList: [], // records
page: {
currentPage: 1,
pageSize: 10,
totalRecord: 0,
totalPage: 0,
cursor: 0,
records: []
}
},
...
},
effects: {
/** 获取RPC信息列表 */
* getRpcsList({ payload }, { call, put }) {
const {
produceId, // 模块id
searchWord,
page = {
from: 1,
to: 1,
size: 10
}
} = payload;
if (produceId) {
const { data } = yield call(
service.getRpcsList,
{
produceId, // 模块id
searchWord,
page
}
);
yield put({ type: 'setRpcsList', payload: { data } });
}
},
...
},
reducers: {
/** 设置RPC信息列表 */
setRpcsList(state, { payload: { data } }) {
const {
page: {
current, size, total, recordCount
},
records,
} = data;
return {
...state,
rpcsList: {
...state.rpcsList,
rpcList: [...records],
page: {
...state.rpcsList.page,
currentPage: current,
pageSize: size,
totalRecord: recordCount, // item总数
totalPage: total, // 总页数
},
}
};
},
...
},
subscriptions: {
setup({ dispatch, history }) {
return history.listen(async ({ pathname, query }) => {
const regex = /\/rpc\/([\w-_]+)/g;
const { omProductId } = query;
if (omProductId) {
if (regex.test(pathname)) {
switch (RegExp.$1) {
case 'rpcs':
if (pathname === '/rpc/rpcs') {
const { id } = await dispatch({
type: 'global/getCurrentProduct',
payload: { omProductId }
});
dispatch({
type: 'getRpcsList',
payload: {
produceId: id,
page: {
from: 1,
to: 1,
size: 10
}
}
});
break;
...
default:
break;
}
}
}
});
}
}
};
第五步:边开发边学
看懂了前面这些内容,你基本就可以开始介入开发了。照葫芦画瓢大法和Ctrl C+Ctrl V大法,可以帮你轻松实现一些页面和组件。但是,知其然不知其所以然依旧不是学习的态度,所以我们要在开发过程中不断去学习。
我是先从react学起,边看视频边敲代码边对比项目工程(感兴趣的可以看下我整理的学习笔记:「React」万字保姆级基础教程>1 和 「React」万字保姆级基础教程>2),看完绝对让你感觉写react就是一种享(zhe)受(mo)
然后学习DvaJS 、 ECMAScript6(ES6) 、 UmiJS 和 UmiMax
这套闪电五连鞭组合拳下来,保证你醉生梦死 😎
第六步:道阻且长行则将至
因为还有一个老的测试平台(Vue的)在我这里维护,所以楼主又额外学习了Vue知识(学习方法同上)
看再多学习视频、整理再多笔记,都不如做一个项目学得快。所以各位一定记住,多写代码、多写代码、多写代码!
“Talk is cheap, show me the code” -- 布施沃硕德
转载自:https://juejin.cn/post/7223390625881194553