版权声明:[email protected] https://blog.csdn.net/qq_37615098/article/details/84888606
代码:
import requests
from cfg import g_vcode
from pprint import pprint
from robot.api import logger
from robot.libraries.BuiltIn import BuiltIn
class SchoolClassLib: #通常用类实现关键字库,类名和文件名相同
URL = "http://ci.ytesting.com/api/3school/school_classes" #可以写在类的静态属性里面,也可以写在cfg的变量文件里面
def __init__(self): #定义一个初始化方法
self.vcode = g_vcode #也可以直接用全局的变量g_vcode
def set_vcode(self,vcode):
self.vcode = vcode
def delete_school_class(self,classid): #删除班级
payload = {
'vcode' : self.vcode,
}
url = '{}/{}'.format(self.URL,classid) #url加上id,这里是这样构建一下
response = requests.delete(url,data=payload)
return response.json()
def list_school_class(self,gradeid=None): #列出班级
if gradeid != None: #gradeid是可填可不填的,缺省是none
params = { #如果传gradeid
'vcode':self.vcode,
'action':'list_classes_by_schoolgrade',
'gradeid':int(gradeid)
}
else:
params = {
'vcode':self.vcode, #如果不传
'action':'list_classes_by_schoolgrade'
}
response = requests.get(self.URL,params=params) #params就是url请求的参数
bodyDict = response.json() #文档里规定响应是json格式的消息体。.json可以把json字符串转化为py中的对象。得到的是一个字典
# pprint (bodyDict,indent=2) #indent参数就是指定pprint打印出来的参数是两个
logger.debug(f"ret:\n{bodyDict}") #通常的执行就不显示了,报错的时候显示所有
return bodyDict
def add_school_class(self,gradeid,name,studentlimit,idSavedName=None): #添加班级
#最后一个参数就是给添加班级返回的id赋值的变量取一个名字
#这个参数只有一个场景有用(初始化清除),大部分场景都没有用。这是应该用缺省参数
payload = {
'vcode' : self.vcode,
'action' : 'add',
'grade' : int(gradeid),
'name' : name,
'studentlimit' : int(studentlimit),
}
response = requests.post(self.URL,data=payload)
bodyDict = response.json()
pprint (bodyDict,indent=2)
#logger.debug(f"ret:\n{bodyDict}") #通常的执行就不显示了,报错的时候显示所有
if idSavedName: #如果传这个参数
BuiltIn().set_global_variable("${%s}"%idSavedName,bodyDict['id'])
#设置全局变量
return bodyDict
#修改班级接口
def modify_school_class(self,classid,newname,newstudentlimit):
url = f'{self.URL}/{classid}' #字符串拼接url
payload = {
'vcode': self.vcode,
'action': 'modify',
'name': newname,
'studentlimit': int(newstudentlimit),
}
response = requests.put(url,data=payload)
bodyDict = response.json()
pprint(bodyDict,indent=2)
return bodyDict
def delete_all_school_classes(self): #初始化清除,要删除所有的用例
# 先列出所有班级
rd = self.list_school_class()
pprint(rd, indent=2)
# 删除列出的所有班级
for one in rd['retlist']: #文档里面“retlist”:[{},{}] {}里面是一个个班级,id也在里面
self.delete_school_class(one['id']) #获取到id,传给delete
#再列出所有班级
rd = self.list_school_class()
pprint (rd,indent=2)
# 如果没有删除干净,通过异常报错给RF
# 参考http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reporting-keyword-status
if rd['retlist'] != []:
raise Exception("cannot delete all school classes!!")
# def classlist_should_contain(self,
# classlist,
# classname,
# gradename,
# invitecode,
# studentlimit,
# studentnumber,
# classid):
# item = {
# "name":classname,
# "grade__name":gradename,
# "invitecode":invitecode,
# "studentlimit":int(studentlimit),
# "studentnumber":int(studentnumber),
# "id":classid,
# "teacherlist":[]
# }
# if item not in classlist:
# #在rf里面如果要实现一个检查点关键字,怎么表示检查点不通过???就是抛出异常。
# raise Exception("class list dose not contain your class info")
# #里面的东西随便写的
#classlist_should_contain增强版:可能会添加一门课程,多了两条课程,为了解决这种情况。可以加一个参数指定它包含多少次
def classlist_should_contain(self,
classlist,
classname,
gradename,
invitecode,
studentlimit,
studentnumber,
classid,
expectedtimes=1): #可以设置一个缺省值,不写的话只应该包含一次
item = {
"name":classname,
"grade__name":gradename,
"invitecode":invitecode,
"studentlimit":int(studentlimit),
"studentnumber":int(studentnumber),
"id":classid,
"teacherlist":[]
}
occurTimes = classlist.count(item) #看occurTimes在列表里面出现多少次
if occurTimes != expectedtimes: #实际出现的次数和预期的次数是否相等
#在rf里面如果要实现一个检查点关键字,怎么表示检查点不通过???就是抛出异常。
raise Exception(f"班级列表包含了{occurTimes}次指定信息,期望包含{expectedtimes}!!")
#里面的东西随便写的
def classlist_should_not_contain(self,
classlist,
classname,
gradename,
invitecode,
studentlimit,
studentnumber,
classid):
item = {
"name":classname,
"grade__name":gradename,
"invitecode":invitecode,
"studentlimit":int(studentlimit),
"studentnumber":int(studentnumber),
"id":classid,
"teacherlist":[]
}
if item in classlist: #如果在里面的话就会抛出异常
#在rf里面如果要实现一个检查点关键字,怎么表示检查点不通过???就是抛出异常。
raise Exception("class list contain your class info")
#里面的东西随便写的
if __name__ == '__main__': #调试用
scm = SchoolClassLib()
#ret = scm.list_school_class(2)
# ret = scm.add_school_class(1,'新测试',77)
# print(json.dumps(ret, indent=2))
#
#ret = scm.delete_school_class(63630)
# pprint(ret)
# print(json.dumps(ret, indent=2))
#
# ret = scm.list_school_class(1)
# print(json.dumps(ret, indent=2))
# #
#scm.delete_all_school_classes()
#scm.classlist_should_contain()
"""
实现一些个关键字
"""
代码:
import requests,json
from cfg import g_vcode
from pprint import pprint
from robot.api import logger
from robot.libraries.BuiltIn import BuiltIn
class StudentLib: #通常用类实现关键字库,类名和文件名相同
URL = "http://ci.ytesting.com/api/3school/students" #可以写在类的静态属性里面,也可以写在cfg的变量文件里面
def __init__(self): #定义一个初始化方法
self.vcode = g_vcode #也可以直接用全局的变量g_vcode
def set_vcode(self,vcode):
self.vcode = vcode
def list_student(self): #列出学生
params = {
'vcode':self.vcode,
'action':'search_with_pagenation',
}
response = requests.get(self.URL,params=params) #params就是url请求的参数
bodyDict = response.json() #文档里规定响应是json格式的消息体。.json可以把json字符串转化为py中的对象。得到的是一个字典
pprint (bodyDict,indent=2) #indent参数就是指定pprint打印出来的参数是两个
#logger.debug(f"ret:\n{bodyDict}") #通常的执行就不显示了,报错的时候显示所有
return bodyDict
def add_student(self,username,realname,gradeid,classid,phonenumber,idSavedName=None): #添加班级
payload = {
'vcode': self.vcode,
'action': 'add',
'username': username,
'realname': realname,
'gradeid': int(gradeid),
'classid': int(classid),
'phonenumber': phonenumber,
}
response = requests.post(self.URL,data=payload)
bodyDict = response.json()
pprint (bodyDict,indent=2)
#logger.debug(f"ret:\n{bodyDict}") #通常的执行就不显示了,报错的时候显示所有
#需要存储学生id到全局变量中
if idSavedName: #如果传这个参数
BuiltIn().set_global_variable("${%s}"%idSavedName,bodyDict['id'])
print(f"global var set: ${idSavedName}:{bodyDict['id']}")
#设置全局变量,把返回结果的id存到一个变量里面
return bodyDict
#修改学生接口
def modify_student(self,studentid,realname=None,
phonenumber=None,): #=None都是可选的参数,非必填
url = f'{self.URL}/{studentid}' #字符串拼接url
payload = {
'vcode': self.vcode,
'action': 'modify',
}
if realname != None:
payload["realname"] = realname
if phonenumber is not None:
payload["phonenumber"] = phonenumber
response = requests.put(url,data=payload)
bodyDict = response.json()
pprint(bodyDict,indent=2)
return bodyDict
#删除学生
def delete_student(self,studentid): #删除老师
payload = {
'vcode' : self.vcode,
}
url = '{}/{}'.format(self.URL,studentid) #url加上id,这里是这样构建一下
response = requests.delete(url,data=payload)
bodyDict = response.json()
pprint(bodyDict, indent=2)
return bodyDict
#删除所有学生
def delete_all_students(self): #初始化清除,要删除所有的用例
# 先列出所有学生
rd = self.list_student()
# pprint(rd, indent=2)
if rd["retcode"] !=0: #列出老师的接口如果不是正常返回0,就抛异常
raise Exception("cannot list students!!!")
# 删除列出的所有学生
for one in rd['retlist']: #文档里面“retlist”:[{},{}] {}里面是一个个班级,id也在里面
self.delete_student(one['id']) #获取到id,传给delete
#再列出所有学生
rd =self.list_student()
pprint (rd,indent=2)
# 如果没有删除干净,通过异常报错给RF
# 参考http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reporting-keyword-status
if rd['retlist'] != []:
raise Exception("cannot delete all students!!")
# def classlist_should_contain(self,
# classlist,
# classname,
# gradename,
# invitecode,
# studentlimit,
# studentnumber,
# classid):
# item = {
# "name":classname,
# "grade__name":gradename,
# "invitecode":invitecode,
# "studentlimit":int(studentlimit),
# "studentnumber":int(studentnumber),
# "id":classid,
# "teacherlist":[]
# }
# if item not in classlist:
# #在rf里面如果要实现一个检查点关键字,怎么表示检查点不通过???就是抛出异常。
# raise Exception("class list dose not contain your class info")
# #里面的东西随便写的
#classlist_should_contain增强版:可能会添加一门课程,多了两条课程,为了解决这种情况。可以加一个参数指定它包含多少次.
def studentlist_should_contain(self,
studentlist,
username,
realname,
studentid,
phonenumber,
classid,
expectedtimes=1): #可以设置一个缺省值,不写的话只应该包含一次
item = {
"classid":int(classid),
"username":username,
"realname":realname,
"phonenumber":phonenumber,
"id":int(studentid),
}
occurTimes = studentlist.count(item) #看occurTimes在列表里面出现多少次
logger.info("occur {} times".format(occurTimes),also_console=True) #打印到界面上,打印到日志里面
if occurTimes != int(expectedtimes): #实际出现的次数和预期的次数是否相等
#在rf里面如果要实现一个检查点关键字,怎么表示检查点不通过???就是抛出异常。
raise Exception(f'学生列表包含了{occurTimes}次指定信息,期望包含{expectedtimes}!!')
#里面的东西随便写的
# if __name__ == '__main__': #调试用
# scm = StudentLib()
#ret = scm.list_school_class(2)
# ret = scm.add_school_class(1,'新测试',77)
# print(json.dumps(ret, indent=2))
#
#ret = scm.delete_school_class(63630)
# pprint(ret)
# print(json.dumps(ret, indent=2))
#
# ret = scm.list_school_class(1)
# print(json.dumps(ret, indent=2))
# #
#scm.delete_all_school_classes()
#scm.classlist_should_contain()
"""
实现一些个关键字
"""
代码
import requests,json
from cfg import g_vcode
from pprint import pprint
from robot.api import logger
from robot.libraries.BuiltIn import BuiltIn
class TeacherLib: #通常用类实现关键字库,类名和文件名相同
URL = "http://ci.ytesting.com/api/3school/teachers" #可以写在类的静态属性里面,也可以写在cfg的变量文件里面
def __init__(self): #定义一个初始化方法
self.vcode = g_vcode #也可以直接用全局的变量g_vcode
def set_vcode(self,vcode):
self.vcode = vcode
def list_teacher(self,subjectid=None): #列出班级
if subjectid != None: #gradeid是可填可不填的,缺省是none
params = { #如果传gradeid
'vcode':self.vcode,
'action':'search_with_pagenation',
'subjectid':int(subjectid)
}
else:
params = {
'vcode':self.vcode, #如果不传
'action':'search_with_pagenation'
}
response = requests.get(self.URL,params=params) #params就是url请求的参数
bodyDict = response.json() #文档里规定响应是json格式的消息体。.json可以把json字符串转化为py中的对象。得到的是一个字典
pprint (bodyDict,indent=2) #indent参数就是指定pprint打印出来的参数是两个
#logger.debug(f"ret:\n{bodyDict}") #通常的执行就不显示了,报错的时候显示所有
return bodyDict
def add_teacher(self,username,realname,subjectid,classlist,phonenumber,email,
idcardnumber,idSavedName=None): #添加班级
#最后一个参数就是给添加班级返回的id赋值的变量取一个名字
#这个参数只有一个场景有用(初始化清除),大部分场景都没有用。这是应该用缺省参数
classlist = str(classlist)
newClassList = [{"id": oneid} for oneid in classlist.split(",") if oneid] #构建一个列表对象,这里面的classlist是字符串类似于"230,231"
payload = {
'vcode' : self.vcode,
'action' : 'add',
'username' : username,
'realname' : realname,
'subjectid' : int(subjectid),
'classlist': json.dumps(newClassList), #json就是一个字符串,只不过符合了py代码的字符串。dumps(newClassList)就变成了,json格式的字符串,一dumps就变成了符合json格式的字符串
'phonenumber': phonenumber,
'email': email,
'idcardnumber': idcardnumber,
}
response = requests.post(self.URL,data=payload)
bodyDict = response.json()
pprint (bodyDict,indent=2)
#logger.debug(f"ret:\n{bodyDict}") #通常的执行就不显示了,报错的时候显示所有
if idSavedName: #如果传这个参数
BuiltIn().set_global_variable("${%s}"%idSavedName,bodyDict['id'])
#设置全局变量,把返回结果的id存到一个变量里面
return bodyDict
#修改老师接口
def modify_teacher(self,teacherid,
realname=None,
subjectid=None,
classlist=None,
phonenumber=None,
email=None,
idcardnumber=None): #=None都是可选的参数,非必填
url = f'{self.URL}/{teacherid}' #字符串拼接url
payload = {
'vcode': self.vcode,
'action': 'modify',
}
if realname is not None:
payload["realname"] = realname
if subjectid is not None:
payload["subjectid"] =int(subjectid)
if phonenumber is not None:
payload["phonenumber"] = phonenumber
if email is not None:
payload["email"] = email
if idcardnumber is not None:
payload["idcardnumber"] = idcardnumber
#'1,2,3'
if classlist is not None:
newClassList = [{"id": oneid} for oneid in classlist.split(",") if oneid]
payload["classlist"] = json.dumps(newClassList)
response = requests.put(url,data=payload)
bodyDict = response.json()
pprint(bodyDict,indent=2)
return bodyDict
#删除老师
def delete_teacher(self,teacherid): #删除老师
payload = {
'vcode' : self.vcode,
}
url = '{}/{}'.format(self.URL,teacherid) #url加上id,这里是这样构建一下
response = requests.delete(url,data=payload)
bodyDict = response.json()
pprint(bodyDict, indent=2)
return bodyDict
#删除所有老师
def delete_all_teachers(self): #初始化清除,要删除所有的用例
# 先列出所有班级
rd = self.list_teacher()
pprint(rd, indent=2)
if rd["retcode"] !=0: #列出老师的接口如果不是正常返回0,就抛异常
raise Exception("cannot list teachers!!!")
# 删除列出的所有老师
for one in rd['retlist']: #文档里面“retlist”:[{},{}] {}里面是一个个班级,id也在里面
self.delete_teacher(one['id']) #获取到id,传给delete
#再列出所有老师
rd =self.list_teacher()
pprint (rd,indent=2)
# 如果没有删除干净,通过异常报错给RF
# 参考http://robotframework.org/robotframework/latest/RobotFrameworkUserGuide.html#reporting-keyword-status
if rd['retlist'] != []:
raise Exception("cannot delete all school classes!!")
# def classlist_should_contain(self,
# classlist,
# classname,
# gradename,
# invitecode,
# studentlimit,
# studentnumber,
# classid):
# item = {
# "name":classname,
# "grade__name":gradename,
# "invitecode":invitecode,
# "studentlimit":int(studentlimit),
# "studentnumber":int(studentnumber),
# "id":classid,
# "teacherlist":[]
# }
# if item not in classlist:
# #在rf里面如果要实现一个检查点关键字,怎么表示检查点不通过???就是抛出异常。
# raise Exception("class list dose not contain your class info")
# #里面的东西随便写的
#classlist_should_contain增强版:可能会添加一门课程,多了两条课程,为了解决这种情况。可以加一个参数指定它包含多少次.
def teacherlist_should_contain(self,
teacherlist,
username,
realname,
id,
teachclasslist,
phonenumber,
email,
idcardnumber,
expectedtimes=1): #可以设置一个缺省值,不写的话只应该包含一次
#1,2,3 确保是字符串,而不是整数
teachclasslist = str(teachclasslist)
item = {
"username":username,
"realname":realname,
"id":int(id),
"teachclasslist":[int(one) for one in teachclasslist.split(",")], #要符合接口文档里面[230,231],传进来是1,2,3的格式
"phonenumber":phonenumber,
"email":email,
"idcardnumber":idcardnumber
}
occurTimes = teacherlist.count(item) #看occurTimes在列表里面出现多少次
logger.info("occur {} times".format(occurTimes),also_console=True) #打印到界面上,打印到日志里面
if occurTimes != expectedtimes: #实际出现的次数和预期的次数是否相等
#在rf里面如果要实现一个检查点关键字,怎么表示检查点不通过???就是抛出异常。
raise Exception("teacherlist list contain your teacher info {} times,expect {} times,expect{}times!!".format(occurTimes,expectedtimes))
#里面的东西随便写的
# def classlist_should_not_contain(self,
# classlist,
# classname,
# gradename,
# invitecode,
# studentlimit,
# studentnumber,
# classid):
# item = {
# "name":classname,
# "grade__name":gradename,
# "invitecode":invitecode,
# "studentlimit":int(studentlimit),
# "studentnumber":int(studentnumber),
# "id":classid,
# "teacherlist":[]
# }
# if item in classlist: #如果在里面的话就会抛出异常
# #在rf里面如果要实现一个检查点关键字,怎么表示检查点不通过???就是抛出异常。
# raise Exception("class list contain your class info")
# #里面的东西随便写的
#
if __name__ == '__main__': #调试用
scm = TeacherLib()
#ret = scm.list_school_class(2)
# ret = scm.add_school_class(1,'新测试',77)
# print(json.dumps(ret, indent=2))
#
#ret = scm.delete_school_class(63630)
# pprint(ret)
# print(json.dumps(ret, indent=2))
#
# ret = scm.list_school_class(1)
# print(json.dumps(ret, indent=2))
# #
#scm.delete_all_school_classes()
#scm.classlist_should_contain()
"""
实现一些个关键字
"""
代码
from selenium import webdriver
from cfg import *
import time
import pprint
class WebOpLib:
ROBOT_LIBRARY_SCOPE = 'GLOBAL'
# 申明一个静态的成员,只会创建一个实例
def __init__(self):
pass
# 方便导入库的时候,传入参数
def open_browser(self):
self.wd = webdriver.Chrome()
self.wd.implicitly_wait(10)
def close_browser(self):
self.wd.quit()
def teacher_login(self, username, password): # 老师登录
self.wd.get(g_teacher_login_url) # 输入网址
self.wd.find_element_by_id("username").send_keys(username) # 用户名
self.wd.find_element_by_id("password").send_keys(password) # 密码
self.wd.find_element_by_id("submit").click() # 点击登录
self.wd.find_element_by_id('topbar')
def get_teacher_homepage_info(self): # 首页内容的获取
self.wd.find_element_by_css_selector('a[href="#/home"]>li').click()
self.wd.find_element_by_id("home_div")
time.sleep(2)
eles = self.wd.find_elements_by_css_selector(".ng-binding")
return [ele.text for ele in eles] # 返回所有得class为.ng-binding的元素文本,方便验证
def get_teacher_class_students_info(self): # 获取班级里学生信息
self.wd.find_element_by_css_selector('.main-menu >ul> li:nth-of-type(4)').click()
self.wd.find_element_by_css_selector('a[href="#/student_group"] span').click()
time.sleep(2)
self.wd.implicitly_wait(1)
classes = self.wd.find_elements_by_css_selector('div.panel')
# 找老师所教的班级,返回的是列表
self.wd.implicitly_wait(10)
# if not classes:
# return {} #如果是空列表就返回空字典,可以去掉
#
classStudentTab = {}
for cla in classes:
gradeclass = cla.find_element_by_class_name('panel-heading').text.replace(' ', '')
# 获取元素的文本信息,并把空格去掉
cla.click()
time.sleep(2)
self.wd.implicitly_wait(1)
Eles = cla.find_elements_by_css_selector('tr > td:nth-child(2)')
self.wd.implicitly_wait(10)
names = [Ele.text for Ele in Eles] # 每个元素取出来,把文本拿出来
classStudentTab[gradeclass] = names # 每个循环都生成一个键值对{gradeclass:names}
return classStudentTab
def student_login(self, username, password): # 学生登录
self.wd.get(g_student_login_url) # 输入网址
self.wd.find_element_by_id("username").send_keys(username) # 用户名
self.wd.find_element_by_id("password").send_keys(password) # 密码
self.wd.find_element_by_id("submit").click() # 点击登录
def get_student_homepage_info(self):
# 查看 a 元素发现其位置不是主页按钮位置
self.wd.find_element_by_css_selector("a[href='#/home']>li").click()
# 确保首页打开
# 由于数据是异步获取,需要sleep一段时间,假设需求是2秒必须获取数据
time.sleep(2)
eles = self.wd.find_elements_by_css_selector('#div-home .ng-binding')
ret = [ele.text for ele in eles]
ret.pop(2) # 把注册码去掉
return ret
def get_student_wrongquestions(self):
self.wd.find_element_by_css_selector('a[href="#/yj_wrong_questions"] >li').click()
# 由于数据是异步获取,需要sleep一段时间,假设需求是2秒必须获取数据
time.sleep(2)
return self.wd.find_element_by_id('page-wrapper').text
def teacher_deliver_task(self,
examname):
self.wd.find_element_by_css_selector('.main-menu >ul> li:nth-of-type(2)').click()
self.wd.find_element_by_css_selector('a[ng-click^="show_page_addexam"] span').click()
time.sleep(2)
self.wd.find_element_by_id('exam_name_text').send_keys(examname)
self.wd.find_element_by_id('btn_pick_question').click()
# 点击后界面重新渲染,等待一下
time.sleep(2)
# 题目在新的frame中
self.wd.switch_to.frame('pick_questions_frame')
# 只需要选前3个
# 每次选择一题,界面会重新渲染,所以只能循环获取
for counter in range(3):
selectButtons = self.wd.find_elements_by_class_name('btn_pick_question')
selectButtons[counter].click()
# 点击后界面重新渲染,等待一下
time.sleep(2)
# 点击 oK button
self.wd.find_element_by_css_selector(
'div.btn-blue[onclick*="pickQuestionOK"'
).click()
# 切换回 主 html
self.wd.switch_to.default_content()
# 选完题目回到主界面,界面会发生变动,sleep 一下
time.sleep(1)
# 点击确定添加
self.wd.find_element_by_id('btn_submit').click()
# 选择发布给学生
self.wd.find_element_by_css_selector(
'div.bootstrap-dialog .bootstrap-dialog-footer-buttons button:nth-child(2)'
).click()
# sleep 一下
time.sleep(1)
# 切换到 下发学习任务窗口
# 保存主窗口handle
mainWindow = self.wd.current_window_handle
for handle in self.wd.window_handles:
# 切换到新窗口
self.wd.switch_to.window(handle)
# 检查是否是我们要进入的window
if '下发学习任务' in self.wd.title:
print('进入到下发任务窗口')
break
# sleep 一下
time.sleep(1)
# 只有唯一的一位学生,直接勾选即可
# 注意要选 label.myCheckbox 而不是 input[type=checkbox]
# 因为后者不可见,调试就会发现问题
self.wd.find_element_by_css_selector('label.myCheckbox').click()
# 点击确定下发
self.wd.find_element_by_css_selector('button[ng-click*=openDispatchDlg]').click()
# sleep 一下
time.sleep(1)
# 点击确定
self.wd.find_element_by_css_selector('button[ng-click*=dispatchIt]').click()
# 下一个确定
self.wd.find_element_by_css_selector(
'div.bootstrap-dialog-footer-buttons > button').click()
# 切回主窗口
self.wd.switch_to.window(mainWindow)
def studentDoExam(self):
self.wd.find_element_by_css_selector('a[href="#/task_manage"] >li').click()
# 由于数据是异步获取,需要sleep一段时间,假设需求是2秒必须获取数据
time.sleep(2)
# 点击打开第一个任务
self.wd.find_element_by_css_selector('button[ng-click*=viewTask]').click()
# 全部选A
firstAnwsers = self.wd.find_elements_by_css_selector(
'.btn-group button:nth-child(1)'
)
for one in firstAnwsers:
one.click()
self.wd.find_element_by_css_selector('button[ng-click*=saveMyResult]').click()
# 点击确定
self.wd.find_element_by_css_selector(
'div.bootstrap-dialog .bootstrap-dialog-footer-buttons button:nth-child(2)'
).click()
time.sleep(2)
def teacher_get_latest_student_task(self):
self.wd.get('http://ci.ytesting.com/teacher/index.html#/task_manage?tt=1')
time.sleep(2)
# 点击第一个任务查看
self.wd.find_element_by_css_selector(
"a[ng-click*=trackTask]"
).click()
time.sleep(1)
# 点击 第一个学生 查看
self.wd.find_element_by_css_selector(
'button[ng-click*="viewTaskTrack"]'
).click()
# 切换到 查看作业窗口
# 保存主窗口handle
mainWindow = self.wd.current_window_handle
for handle in self.wd.window_handles:
# 切换到新窗口
self.wd.switch_to.window(handle)
# 检查是否是我们要进入的window
if '查看作业' in self.wd.title:
break
# 勾选的选项会有 .myCheckbox input:checked 风格修饰,
# 但是这个不出现在 元素html里面
eles = self.wd.find_elements_by_css_selector('.myCheckbox input:checked')
selectedchoices = [ele.find_element_by_xpath('./..').text.strip() for ele in eles]
print(selectedchoices)
# 切回主窗口
self.wd.switch_to.window(mainWindow)
return selectedchoices
if __name__ == '__main__':
wo = WebOpLib()
wo.open_browser()
wo.teacher_login('tuobagui','888888')
wo.teacher_deliver_task('测试作业第3个')
#
#
# wo.student_login('xiexuan','888888')
# wo.studentDoExam()
#
#
#
# wo.teacher_login('tuobajun','888888')
# wo.teacher_get_latest_student_task()
代码:
*** Settings ***
Library pylib.StudentLib
Variables cfg.py
Suite Setup add student xiexuan01 谢玄01
... ${g_grade_7_id}
... ${suite_g7c1_classid} 13200000001
... suit_student_id
Suite Teardown delete student ${suit_student_id}
#先创建一个老师在删除
#${g_subject_math_id}
代码:
*** Settings ***
Library pylib.WebOpLib
Library pylib.TeacherLib
Variables cfg.py
Suite Setup open_browser
Suite Teardown close_browser
*** Test Cases ***
老师登录2 - tc005002
${addRet}= add_teacher tuobagui 拓跋珪
... ${g_subject_math_id}
... ${suite_g7c1_classid}
#上面是所教班级id
... 13002021526 [email protected] 3208821966
should be true $addRet['retcode']==0
teacher login tuobagui 888888
${ateacherinfo}= get teacher homepage info
#获取的是老师首页的几处文字:名字,学校,姓名,金币
${eteacherinfo}= create list 拓跋珪 松勤学院0273 拓跋珪 初中数学 0 0 0
should be equal ${ateacherinfo} ${eteacherinfo}
${classStudent}= get teacher class students info
#获取班级学生
#班级里有一个学生
should be true $classStudent=={"七年级1班":["谢玄01"]}
[Teardown] delete teacher &{addRet}[id]
代码:
*** Settings ***
Library pylib.StudentLib
Variables cfg.py
Suite Setup add student xiexuan01 谢玄01
... ${g_grade_7_id}
... ${suite_g7c1_classid} 13200000001
... suit_student_id
Suite Teardown delete student ${suit_student_id}
#先创建一个老师在删除
#${g_subject_math_id}
代码:
*** Settings ***
Library pylib.WebOpLib
Variables cfg.py
Suite Setup open_browser
Suite Teardown close_browser
*** Test Cases ***
老师发布作业1 - tc005101
teacher_login tuobagui 888888
teacher_deliver_task 测试作业第1个
student_login xiexuan01 888888
studentDoExam
teacher_login tuobagui 888888
${choices}= teacher_get_latest_student_task
should be true $choices==['A', 'A', 'A']
代码:
*** Settings ***
Library pylib.StudentLib
Variables cfg.py
*** Test Cases ***
添加学生2 - tc002002
#添加学生到7年级一班,还没有学生
#测试,造数据用:老师:tuobagui 学生:xiexuan01
${addRet}= add student xielinyun03 谢灵运03
... ${g_grade_7_id}
... ${suite_g7c1_classid} 13200000001
should be true $addRet['retcode']==0
${listRet}= list student
#第一种写法
# should be true $listRet['retlist']==[{"classid":${suite_g7c1_classid},"username":"xielinyun01","realname":"谢灵运01","phonenumber":"13200000001","id":${addRet}['id']}]
# #之前里面没有课程,添加了之后就是一个课程
#第二种写法
studentlist_should_contain &{listRet}[retlist]
... xielinyun03 谢灵运03 &{addRet}[id]
... 13200000001 ${suite_g7c1_classid}
[Teardown] delete_student &{addRet}[id]
删除学生1 - tc002081
#添加学生到7年级一班,还没有学生
#添加学生
${addRet}= add student xielinyun40 谢灵运40
... ${g_grade_7_id}
... ${suite_g7c1_classid} 13200000001
should be true $addRet['retcode']==0
#列出学生
${listRet}= list student
studentlist_should_contain &{listRet}[retlist]
... xielinyun40 谢灵运40 &{addRet}[id]
... 13200000001 ${suite_g7c1_classid}
#删除学生
${delRet}= delete_student &{addRet}[id]
should be true $delRet["retcode"]==0
#再列出学生,列表里包含谢灵运04的个数是0,就是不在这个列表里面
${listRet}= list student
studentlist_should_contain &{listRet}[retlist]
... xielinyun40 谢灵运40 &{addRet}[id]
... 13200000001 ${suite_g7c1_classid} 0
代码:
*** Settings ***
Library pylib.TeacherLib
Variables cfg.py
Suite Setup add teacher tuobagui 拓跋珪
... ${g_subject_math_id}
... ${suite_g7c1_classid}
... 13002021526 [email protected] 3208821966
... suite_math_teacher_id
Suite Teardown delete teacher ${suite_math_teacher_id}
#先创建一个老师在删除
#${g_subject_math_id}
*** Settings ***
Library pylib.StudentLib
Variables cfg.py
*** Test Cases ***
添加学生1 - tc002001
#添加学生到7年级一班,还没有学生
${addRet}= add student xielinyun01 谢灵运01
... ${g_grade_7_id}
... ${suite_g7c1_classid} 13200000001
should be true $addRet['retcode']==0
${listRet}= list student
#第一种写法
# should be true $listRet['retlist']==[{"classid":${suite_g7c1_classid},"username":"xielinyun01","realname":"谢灵运01","phonenumber":"13200000001","id":${addRet}['id']}]
# #之前里面没有课程,添加了之后就是一个课程
#第二种写法
studentlist_should_contain &{listRet}[retlist]
... xielinyun01 谢灵运01 &{addRet}[id]
... 13200000001 ${suite_g7c1_classid}
[Teardown] delete_student &{addRet}[id]
代码:
*** Settings ***
Library pylib.TeacherLib
Variables cfg.py
*** Test Cases ***
添加老师2 - tc001002
${addRet}= add_teacher murongba 慕容霸
... ${g_subject_science_id}
... ${suite_g7c1_classid}
#上面是所教班级id
... 13002021501 [email protected] 3208821902
should be true $addRet['retcode']==0
${listRet}= list_teacher
teacherlist should contain &{listRet}[retlist]
... murongba 慕容霸 &{addRet}[id]
... ${suite_g7c1_classid}
... 13002021501 [email protected] 3208821902
[Teardown] delete_teacher &{addRet}[id]
添加老师3 - tc001003
${listRet1}= list teacher
${addRet}= add_teacher tuobagui 拓跋珪
... ${g_subject_science_id}
... ${suite_g7c1_classid}
#上面是所教班级id
... 13002021501 [email protected] 3208821902
should be true $addRet['retcode']==1
should be true $addRet['reason']=="登录名 tuobagui 已经存在"
${listRet2}= list_teacher
should be equal ${listRet1} ${listRet2}
删除老师1 - tc001081
#删除一个id号不存在的老师
#列出老师
${listRet1}= list teacher
#删除老师,不存在的ID
${delRet}= delete teacher 99999999
should be true $delRet['retcode']==404
should be true $delRet['reason']=="id 为`99999999`的老师不存在"
#列出老师,检验一下
${listRet2}= list teacher
should be equal ${listRet1} ${listRet2}
删除老师2 - tc001082
#删除一个存在的id,不能删除数据环境里面的环境
#列出老师
${listRet1}= list teacher
# 添加 老师 教7年级1班 科学
${addRet}= add teacher murongke 慕容恪
... ${g_subject_science_id}
... ${suite_g7c1_classid}
... 13000000110 [email protected] 320520110
should be true $addRet['retcode']==0
#删除老师
delete teacher &{addRet}[id]
#列出老师,检验一下
${listRet2}= list teacher
should be equal ${listRet1} ${listRet2}
代码:
#第一种方法,相当于手动设置一个全局变量
#*** keywords ***
#suite setup action
# ${ret}= add_school_class 1 1班 60
# set global variable ${suitesetclassid} &{ret}[id]
#*** Settings ***
#Library pylib.SchoolClassLib
#Suite Setup suite setup action
#Suite Teardown delete_school_class ${suitesetclassid}
#解释
#设置一个全局变量,添加的课程的响应返回值里面的id
# set global variable是设置的全局的
# set suit variable是设置的这个套件的
#第二种方法,因为升级了add_school_class这个关键字,关键字内部可以直接生成一个全局变量。一旦add_school_class的传值有suite_g7c1_classid,就会有一个全局变量suite_g7c1_classid
*** Settings ***
Library pylib.SchoolClassLib
Suite Setup add school class 1 1班 60 suite_g7c1_classid
Suite Teardown delete_school_class ${suite_g7c1_classid}
#最后一个参数,如果添加课程正好用在环境的初始化上面,可以用最后一个参数指定一个全局变量的名字,id是多少,把它保存到一个全局变量里面,这个变量是rf的脚本用的。方便后面使用这个初始化环境添加的id
#测试套件目录 执行结束后,要和执行前一致
#测试套件文件 执行结束后,要和执行前一致
#测试套件用例 执行结束后,要和执行前一致
#这个文件里面是实现添加一个7年级1班的初始化
#实现的用例是创建一个班级,系统中不存在同年级的同名班级
#1是代表7年级,1班,上限不超过60人
#核心就是为了设置一个全局变量,解决了棘手的问题:套件的初始化话,变量没办法存下来的问题
#还有就是初始化里面创建的数据要留给后面用,动态产生的东西,就这样保存下来给后面用
#set_global_variable 全局有效
#set_suite_variable 当前的套件有效,就像d-7年级1班里面的所有的子套件,子用例都有效。通常要限制范围就用set_suite_variable
#set_test_variable 只对当前的用例有效。通常是在用例里面,用的不对。
代码:
*** Settings ***
Library pylib.WebOpLib
Library pylib.TeacherLib
Variables cfg.py
Library pylib.StudentLib
Suite Setup open_browser
Suite Teardown close_browser
*** Test Cases ***
老师登录1 - tc005001
${addRet}= add_teacher tuobagui 拓跋珪
... ${g_subject_math_id}
... ${suite_g7c1_classid}
#上面是所教班级id
... 13002021526 [email protected] 3208821966
should be true $addRet['retcode']==0
teacher login tuobagui 888888
${ateacherinfo}= get teacher homepage info
#获取的是老师首页的几处文字:名字,学校,姓名,金币
${eteacherinfo}= create list 拓跋珪 松勤学院0273 拓跋珪 初中数学 0 0 0
should be equal ${ateacherinfo} ${eteacherinfo}
${classStudent}= get teacher class students info
#获取班级学生
should be true $classStudent=={"七年级1班":[]}
[Teardown] delete teacher &{addRet}[id]
学生登录1 --tc005081
${addRet}= add student xiexuan01 谢玄01
... ${g_grade_7_id}
... ${suite_g7c1_classid} 13200000001
student login xiexuan01 888888
${studentinfo}= get_student_homepage_info
# log to console ${studentinfo} #调试
should be true $studentinfo==["谢玄01","松勤学院0273","0","0"]
${wrongquestions}= get_student_wrongquestions
should be true $wrongquestions=="您尚未有错题入库哦"
[Teardown] delete student &{addRet}[id]
代码:
*** Settings ***
Library pylib.SchoolClassLib
*** Test Cases ***
#添加班级2 - tc000002
# ${ret1}= add school class 1 2班 60
# should be true $ret1['retcode']==0
#
##列出班级,和添加的班级检验一下,id一致,邀请码一致
# ${ret2}= list school class 1
# should be true {'name': '2班', 'grade__name': '七年级', 'invitecode': $ret1['invitecode'], 'studentlimit': 60, 'studentnumber': 0, 'id': $ret1['id'], 'teacherlist': []}in $ret2['retlist']
##列出班级的响应是这样的:(见图文档规定)
##rf的写法实在不是容易的事情,rf不擅长处理复杂的数据,不能换行。
##最好是通过其他的方法来实现
# [Teardown] delete_school_class &{ret1}[id]
##&{ret1}是添加课程产生的字典,取出id删掉
#第二种简单,方便,基于py的写法,用关键字实现。
添加班级2 - tc000002
${ret1}= add school class 1 2班 60
should be true $ret1['retcode']==0
#验证状态码是不是0
#列出班级,检验一下
${ret2}= list school class 1
${retlist}= evaluate $ret2['retlist']
#把响应里面的retlist取出来,赋值到变量里面
classlist should contain ${retlist}
... 2班 七年级 &{ret1}[invitecode] 60 0 &{ret1}[id]
#...是换行,后面传的都是参数,$ret1['invitecode']不是py表达式,所以里面不能加引号,从字典里面取数据用&
#实现一个关键字,判断${retlist}里面是否包含2班,七年级。。。这些内容。
[Teardown] delete_school_class &{ret1}[id]
#&{ret1}是添加课程产生的字典,取出id删掉
添加班级3 - tc000003
${ret1}= add school class 1 1班 60
#这里创建的和数据环境里面的是一样的,满足创建一个已有的同名的课程
#should be true $ret1=={"retcode":1,"reason":"duplicated class name"}
#根据文档判断返回值,可以向上面一样写,不能有两个以上的空行,安全起见,也可以分开写
should be true $ret1["retcode"]==1
should be true $ret1["reason"]=="duplicated class name"
#列出班级,检验一下
${ret2}= list school class 1
${retlist}= evaluate $ret2['retlist']
#实现关键字classlist should not contain ,列出的列表里面不包含下面的信息(就是添加的信息)
classlist should not contain ${retlist}
... 1班 七年级 &{ret1}[invitecode] 60 0 &{ret1}[id]
#[Teardown]清除的操作就不要了,应该是添加不成功的。也没法根据id来删除
修改班级1 - tc000051
#添加7年级2班
${ret1}= add school class 1 2班 60
should be true $ret1['retcode']==0
${classid}= evaluate $ret1["id"]
#修改为7年级222班
${modifyRet}= modify_school_class ${classid} 222班 60
should be true $modifyRet['retcode']==0
#列出班级,检验一下
${ret2}= list school class 1
${retlist}= evaluate $ret2['retlist']
#把响应里面的retlist取出来,赋值到变量里面
classlist should contain ${retlist}
... 222班 七年级 &{ret1}[invitecode] 60 0 &{ret1}[id]
[Teardown] delete_school_class ${classid}
修改班级2 - tc000052
#添加7年级2班
${ret1}= add school class 1 2班 60
should be true $ret1['retcode']==0
${classid}= evaluate $ret1["id"]
#先列出班级
${listret1}= list school class 1
#修改为7年级1班
${modifyRet}= modify_school_class ${classid} 1班 60
should be true $modifyRet['retcode']==1
should be true $modifyRet["reason"]=="duplicated class name"
#再列出班级,和之前列出的班级比较下,是一样的话,就说明修改没有成功。就是正确的
${listret2}= list school class 1
should be equal ${listret1} ${listret2}
[Teardown] delete_school_class ${classid}
#这个用例执行不通过,就是系统的bug,返回的状态码是10000
修改班级3 - tc000053
#修改id号不存在的班级,可以写一个很大的数字
${modifyRet}= modify_school_class 9999 1班 60
should be true $modifyRet["retcode"]==404
should be true $modifyRet['reason']=='id 为`9999`的班级不存在'
# log to console ${modifyRet} 可以打印出来看看,9999上面的符号有点坑
删除班级1 - tc000081
#删除id号不存在的班级,也可以写一个很大的数字
${delRet}= delete school class 9999
should be true ${delRet}["retcode"]==404
should be true ${delRet}['reason']=='id 为`9999`的班级不存在'
# log to console ${modifyRet} 可以打印出来看看,9999上面的符号有点坑
删除班级2 - tc000082
#添加7年级2班
${ret1}= add school class 1 2班 60
should be true $ret1['retcode']==0
${classid}= evaluate $ret1["id"]
#先列出班级
${listret1}= list school class 1
${retlist}= evaluate $listret1["retlist"]
classlist should contain ${retlist}
... 2班 七年级 &{ret1}[invitecode] 60 0 &{ret1}[id]
#删除为7年级2班
${delRet}= delete school class ${classid}
should be true $delRet['retcode']==0
#列出班级,检验一下
${listret2}= list school class 1
${retlist}= evaluate $listret2['retlist']
#把响应里面的retlist取出来,赋值到变量里面
classlist_should_not_contain ${retlist}
... 2班 七年级 &{ret1}[invitecode] 60 0 &{ret1}[id]
代码:
*** Settings ***
Library pylib.TeacherLib
Variables cfg.py
*** Test Cases ***
添加老师1 - tc001001
${addRet}= add_teacher tuobagui 拓跋珪
... ${g_subject_math_id}
... ${suite_g7c1_classid}
#上面是所教班级id
... 13002021526 [email protected] 3208821966
should be true $addRet['retcode']==0
${listRet}= list_teacher
teacherlist should contain &{listRet}[retlist]
... tuobagui 拓跋珪 &{addRet}[id]
... ${suite_g7c1_classid}
... 13002021526 [email protected] 3208821966
[Teardown] delete_teacher &{addRet}[id]
代码:
*** Settings ***
Library pylib.SchoolClassLib
Library pylib.TeacherLib
Library pylib.StudentLib
Suite Setup Run Keywords delete all students AND
... delete all teachers AND
... delete_all_school_classes
#老师和班级,先删除老师。才能删除班级。文档里面有
#老师和学生都依赖于班级
*** Settings ***
Library pylib.SchoolClassLib
*** Test Cases ***
添加班级1 - tc000001
${ret1}= add school class 1 1班 60
should be true $ret1[‘retcode’]==0
#列出班级,和添加的班级检验一下,id一致,邀请码一致
${ret2}= list school class 1
${fc}= evaluate $ret2[‘retlist’][0]
should be true
ret1[‘id’]
should be true
ret1[‘invitecode’]
#将垃圾数据清除掉,不要破坏空白数据环境
[Teardown] delete_school_class &{ret1}[id]
#&{ret1}是添加课程产生的字典,取出id删掉
代码:
g_vcode = '00000002775300822470'
g_subject_math_id = 1 #学科数学的id是1,可读性更好
g_subject_science_id = 5
g_grade_7_id = 1 #7年级的id是1,可读性更好
g_teacher_login_url = "http://ci.ytesting.com/teacher/login/login.html"
g_student_login_url = "http://ci.ytesting.com/student/login/login.html"
"""
全局的变量可以g-开头
"""
完整代码:
https://pan.baidu.com/s/1kXxFGBtjgJaKLGPgNvcZlQ
参考代码完整,用例,接口文档:
https://pan.baidu.com/s/1w6wzNlT06Iu3xfBxT9Sl6Q