Postman
Postman实现接口关联
- 步骤
- 通过正则表达式或则JSON提取器取值的方式,提取需要的参数。
- 将参数设置为全局变量或则环境变量。
- 在之后接口中,通过{{全局变量/环境变量}}代替要替换的参数值。
- JSON提取器方式
var jsonData = JSON.parse(responseBody);
pm.environment.set("token",jsonData.data.accessToken);
- 正则表达式
var jsonData = reponseBody.match(new RegExp('"accessToken":(*.?)'));
pm.globals.set("token",jsonData[1])
Postman实现参数化
- 内置函数。
- {{$randomint}}:添加0-1000之间的随机整数。
- {{$guid}}:添加一个V4风格的GUID
- {{$timestamp}}: 添加当前的时间戳,精确到秒
- {{$randomFullName}}:随机全名(名字 姓氏)
- {{ $randomBoolean}}: 随机布尔值 (true/false)
- Pre-request-Script页签中使用代码实现
- 前置脚本设置自定义变量。
- 全局变量/环境变量/Collection变量
- 后置脚本设置提取变量。
- CSV/JSON文件。
- 关键点1:{{变量名}}:变量名同CSV第一行设置的变量名和JSON文件设置变量名。
- 关键点2:通过Run Configuration->Data导入文件->设置Iterations。
Jmeter
Jmeter实现接口关联
- 步骤
- 在测试计划中添加一个线程组,然后添加取样器。
- 对线程组右键添加后置处理器→正则表达式提取器/JSON提取器/Xpath提取器。
- APPly to:作用范围:
- Main sample and sub-samples:作用于父节点的取样器及对应子节点的取样器
- Main sample only:仅作用于父节点的取样器
- Sub-samples only:仅作用于子节点的取样器
- JMeter Variable:作用于jmeter变量(输入框内可输入jmeter的变量名称)
- 要检查的响应字段:
- Body(unescaped):主体
- Body as a Document:从不同类型的文件中提取文本
- Response Headers:响应信息头
- Request Headers:请求信息头
- URL:统一资源定位符
- 模板:
- $0$代表这一组结果的全部,
- $1$代表这一组结果的第1个,以此类推;
- $1$$2$代表该正则表达式一组结果中的第1个和第2个,俩结果挨在一起中间没有间隔;
- $3$,$4$代表该正则表达式一组结果中的第3个和第4个,俩结果间有一个逗号相连。
- Variable names : 名称
- JSONPath Expression:JSON表达式
- Match Numbers:匹配哪个,可为空即默认第一个
- Default Value:未取到值的时候默认值
- 正则表达式提取器
- `<title>百度一下,你就知道</title><title>百度一下,你就知道</title>` -> `<title>(.*?)</title>`
- `021-1234-1234`->`(.*?)-(.*?)-(.*?)\n`
- XPath提取器
- `//a[@id='kw']: 在HTML页面中,找出a标签(有一个属性为id,且id的值为kw)`
- ` //a : 找出所有的a标签`
- JSON提取器
Jmeter实现参数化
-
用户定义的变量:
- 作用:定义全局变量。
- 局限性:每次取值(无论是否相同的用户)都是固定值。
-
用户参数:
- 作用:保证不同的用户针对同一组参数,可以取到不同的值。
- 局限性:同一个用户在多次循环时,取到相同的值。
-
csv数据文件设置:
- 作用:保证不同的用户及同一用户多次循环时,都可以取到不同的值。
- 局限性:需要手动进行测试数据的设置。
-
函数:
- 作用:保证不同的用户及多次循环时,都可以取到不同的值,不需要提前设置
- 局限性:输入数据有特定的业务要求时无法使用(如:登录时的用户名密码)
Selenium参数化
import json
import time
import unittest
from parameterized import parameterized
from ddt.tpshop import utils
from ddt.tpshop.page.login_page import LoginProxy
from ddt.tpshop.utils import DriverUtil
class TestLogin(unittest.TestCase):
def build_data(self):
test_data = []
with open("../data/testData.json", encoding='UTF-8') as f:
json_data = json.load(f)
for login_data in json_data.values():
test_data.append((login_data.get("username"),
login_data.get("password"),
login_data.get("code"),
login_data.get("is_success"),
login_data.get("expect")))
print("test_data=", test_data)
return test_data
@classmethod
def setUpClass(cls):
cls.driver = DriverUtil.get_driver()
cls.login_proxy = LoginProxy()
@classmethod
def tearDownClass(cls):
DriverUtil.quit_driver()
def setUp(self):
# 进入首页
self.driver.get("http://localhost")
# 点击登录链接
self.driver.find_element_by_link_text("登录").click()
@parameterized.expand(self.build_data)
def test_add(self, username, password, code, is_success, expect):
print('username={} password={} code={} is_success={} expect={}'.
format(username, password, code, is_success, expect))
# 登录
self.login_proxy.login(username, password, code)
time.sleep(3)
# 登录成功的用例
if is_success:
self.assertIn(expect, self.driver.title)
else:
# 获取提示框消息
msg = utils.get_tips_msg()
print("msg=", msg)
self.assertIn(expect, msg)
Junit参数化
------------------------------------------------------
@ParameterizedTest
@ValueSource(ints = { 1, 2, 3 })
void test_ValueSource(int i) {
System.out.println(i);
}
------------------------------------------------------
@ParameterizedTest
@EnumSource(ElementType.class)
void test_EnumSource(ElementType et) {
System.out.println(et);
}
------------------------------------------------------
@ParameterizedTest
@EnumSource(value = ElementType.class, names = { "TYPE", "METHOD", "FIELD" })//如果只需要Enum中的特定值,则可以使用EnumSource name参数来实现。
void test_EnumSource_Extended(ElementType et) {
assertTrue(EnumSet.of(ElementType.FIELD, ElementType.TYPE, ElementType.METHOD).contains(et));
}
------------------------------------------------------
@ParameterizedTest
@MethodSource("ms")
void test_MethodSource(String s) {
assertNotNull(s);
}
static Stream<String> ms() {
return Stream.of("A", "B");
}
------------------------------------------------------
@ParameterizedTest
@CsvSource(delimiter='|', value= {"1|'A'","2|B"})
void test_CsvSource(int i, String s) {
assertTrue(3 > i);
assertTrue(Arrays.asList("A", "B", "C").contains(s));
}
-----------------------------------------------------
@ParameterizedTest
@CsvFileSource(resources = "/country_code.csv", numLinesToSkip = 1)
void test_CsvFileSource(String country, int code) {
assertNotNull(country);
assertTrue(0 < code);
}
------------------------------------------------------
SpringBoot
(1)常用注解
- 引导类:
- @SpringBootApplication
- @SpringBootConfiguration
- @EnableAutoConfiguration
- @ComponentScan
- @SpringBootApplication
- 表现层:
- @RestController
- @ResponseBody
- @Controller
- @RequestMapping
- @PostMapping
- @PutMapping
- @PostMapping(“/status/0”)
- @DeleteMapping
- @Autowired
- @RestController
- 业务层:
- @Service
- 数据层;
- @Mapper
- 全局异常处理;
- @ControllerAdvice(annotations = {RestController.class, Controller.class})//表示这是一个aop通知类,做功能增强。
- @ResponseBody//类中方法返回值将以JSON格式返回给前端。
(2)如何实现分页功能
- 为了使用Mybatis-plus提供的分页接口,由于mybatis-plus基于AOP思想仅仅只是对mybatis功能进行增强,因此需要使用分页拦截器,拦截所有查询请求,并使用代理的方式,使用Mybatis-plus提供的接口完成自动分页功能。(mybatis-plus将会注入MybatisPlusInterceptor类型对象,如果没有添加任何拦截器,将不会拦截任何请求)
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return mybatisPlusInterceptor;
}
}
@RestController
@RequestMapping("/employee")
@Slf4j
public class EmployeeController {
@Autowired
private IEmployeeService employeeService;
@GetMapping("/page")
public R<Page> page(int page, int pageSize, String name){
log.info("page = {},pageSize = {},name = {}" ,page,pageSize,name);
//创建一个分页构造器,使用mybatisplus提供的实体。
Page pageInfo = new Page(page,pageSize);
//创建一个条件构造器
LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper();
//添加过滤条件,使用带bool类型的lambda表达式。
queryWrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name);
//添加排序条件
queryWrapper.orderByDesc(Employee::getUpdate_time);
//执行查询
employeeService.page(pageInfo,queryWrapper);
return R.success(pageInfo);
- 总结:
- 构造一个MybatisPlus分页拦截器,交给SpringBoot管理。
- 创建一个MybatisPlus提供的分页构造器。
- 创建一个MybatisPlus提供的条件构造器,然后添加条件。
- 调用MybatisPlus提供的接口page执行查询。
- 返回分页构造器Records中存储着我们想要的分页数据。
(3)解决跨域问题
- 当前浏览器加载页面的URL与当前页面请求的URL不一致(协议/域名/端口不同)。
- 使用@CossOringe解决,一般加载表现层。
(4)MybatisPlus常用注解
- @TableId
- @TableField
- @TableLogic
- @Version
- @OrderBy