xmind测试用例文件转换为csv文件并导入禅道

1、安装python,准备转换文件generate_case_csv_file.py

# -*- coding: utf-8 -*-

import sys
import os
import csv
import json
import hashlib

import requests
from xmindparser import xmind_to_dict


class ZentaoSession(requests.Session):
    url_root = 'http://zentao.tangees.com/zentao/index.php'
    url_login = url_root + '?m=user&f=login&t=json'
    url_get_modules = url_root + '?m=testcase&t=json'
    url_create_modules = url_root + '?m=tree&f=manageChild&root={_id}&view=case&t=json'
    url_pre_page = url_root + '?m=tree&f=browse&productID={_id}&view=case'

        
    def login(self, account, password):
        cred = {
            'account': account,
            'password': hashlib.md5(password.encode('utf8')).hexdigest(),
            'keepLogin[]': 'on'
        }
        r = self.post(self.url_login, data=cred)
        return r.status_code == 200 and r.json()['status'] == 'success'

    def set_product_in_cookies(self, product_name):
        r = self.get(self.url_get_modules)
        if r.status_code == 200 and r.json()['status'] == 'success':
            products = json.loads(r.json()['data'])['products']
            self.product_path_id_map = {v: k for k, v in products.items()}
        if product_name in self.product_path_id_map:
            self.product_id = self.product_path_id_map[product_name]
        else:
            print('项目不存在:' + product_name)
            exit(0)
        temp_cookie = requests.cookies.RequestsCookieJar()
        temp_cookie.set(
            'lastProduct', str(self.product_id),
            domain='zentao.tangees.com', path='/zentao/')
        temp_cookie.set(
            'preProductID', str(self.product_id),
            domain='zentao.tangees.com', path='/zentao/')
        self.cookies.update(temp_cookie)
        return self

    def get_modules_of_product(self, product_name):
        self.set_product_in_cookies(product_name)
        r = self.get(self.url_get_modules)
        if r.status_code == 200 and r.json()['status'] == 'success':
            self.zentao_data = json.loads(r.json()['data'])
            modules = self.zentao_data['modules']
            if modules == ['/']:
                modules = {'0': '/'}
            self.module_path_id_map = {v: k for k, v in modules.items()}
            return self.module_path_id_map
        else:
            print('Failed to get modules of product')
            
    def get_new_modules(self, modules, product_name):
        self.get_modules_of_product(product_name)
        zentao_modules = list(self.module_path_id_map.keys())
        new_modules = [_ for _ in modules if _ not in zentao_modules]
        return new_modules

    def trans_modules_to_tree(self, modules):
        module_tree = {}
        for m in modules:
            m_path = m[1:].split('/')
            current_root = module_tree
            for p in m_path:
                if p not in current_root:
                    current_root[p] = {}
                current_root = current_root[p]
        return module_tree
            
    def create_module_tree(self, module_tree, product_name, pre_module_str=''):
        self.get_modules_of_product(product_name)
        next_layer_modules = list(module_tree.keys())
        must_create_modules = [
            _ for _ in next_layer_modules
            if pre_module_str+'/'+_ not in self.module_path_id_map
        ]
        if len(must_create_modules) > 0:
            if pre_module_str:
                parent_module_id = self.module_path_id_map[pre_module_str]
            else:
                parent_module_id = '0'
            self.create_modules_in_target(
                parent_module_id, must_create_modules
            )
        for k, v in module_tree.items():
            self.create_module_tree(
                v, product_name, pre_module_str=pre_module_str+'/'+k)
    
    def create_modules_in_target(self, parent_id, modules):
        for m in modules:
            url = self.url_create_modules.format(_id=self.product_id)
            print('url: ' + url)
            r = self.post(
                url, data={'modules[]': m, 'parentModuleID': parent_id}
            )
            r.encoding='utf-8'
            if 'alert' in r.text:
                print('在模块%s下创建模块%s时返回警告:%s' % (parent_id, m, str(r.text)))
            else:
                print('在模块%s下创建模块%s成功' % (parent_id, m))
    
    def create_case_modules(self, modules, product_name):
        new_modules = self.get_new_modules(modules, product_name)
        print('需要创建的禅道新用例模块:')
        print(new_modules)
        module_tree = self.trans_modules_to_tree(new_modules)
        self.create_module_tree(module_tree, product_name)
        
    def update_csv_case_module_id(self, csv_file, product_name):
        with open(csv_file, 'r', encoding='gbk') as f:
            reader = csv.reader(f)
            case_list = list(reader)
        self.get_modules_of_product(product_name)
        for case in case_list[1:]:
            if case[0] in self.module_path_id_map:
                case[0] = '%s(#%s)' % (case[0], self.module_path_id_map[case[0]])
            else:
                print('模块不存在或已包含id:' + case[0])
        with open(csv_file, 'w', newline='', encoding='gbk') as csvfile:
            writer = csv.writer(csvfile)
            writer.writerows(case_list)
            print('已更新csv文件中的所属模块,添加了模块id')

def parser_tree_to_list(
    root_value, tree, current_layer, pre_topics, case_list
):
    if 'topics' not in tree:
        pre_topics.pop()
        found_max_layer = current_layer
        return tree['title'], found_max_layer
    else:
        found_max_layer = 0
        tail_topic_list = []
        for node in tree['topics']:
            pre_topics.append(node['title'])
            tail_topic, max_layer = parser_tree_to_list(
                root_value, node, current_layer+1,
                pre_topics, case_list
            )
            found_max_layer = max(found_max_layer, max_layer)
            tail_topic_list.append(tail_topic)
        layer_to_final = found_max_layer - current_layer
        if layer_to_final == 2:
            # 生成步骤和预期
            step_list, expect_list = [], []
            for i, step_and_expect in enumerate(tail_topic_list):
                if isinstance(step_and_expect, str):
                    step_list.append('%d. %s' % (i+1, step_and_expect))
                    expect_list.append('%d. ' % (i+1))
                else:
                    step_list.append('%d. %s' % (i+1, step_and_expect[0]))
                    expect_list.append('%d. %s' % (i+1, step_and_expect[1]))
            title_split_index = -1
            # 生成所属模块
            for mark in  ['成功路径', '失败路径']:
                if mark in pre_topics[:title_split_index]:
                    split_index = pre_topics.index(mark)
                    case_module = '/' + '/'.join(pre_topics[:split_index])
                    break
            else:
                case_module = '/' + '/'.join(pre_topics[:title_split_index-1])

            # 生成关键词
            # if pre_topics[-2] is None:
            #     keyword = root_value
            # else:
            #     keyword = root_value + ';\n' + pre_topics[-2]

            # 添加用例
            case_list.append([
                case_module, None, pre_topics[title_split_index], None, None,
                '-'.join(pre_topics[:title_split_index]),
                '\n'.join(step_list), '\n'.join(expect_list),
                "功能测试", "功能测试阶段"
            ])
            pre_topics.pop()
            return '', found_max_layer
        elif layer_to_final < 2:
            if len(tail_topic_list) > 1:
                print('错误:步骤有多于1个的预期!!!')
                print(str(pre_topics) + ', ' + tree['title'])
                exit(0)
            else:
                pre_topics.pop()
                return [tree['title'], tail_topic_list[0]], found_max_layer
        else:
            pre_topics.pop()
            return '', found_max_layer


def tree_to_case_list(tree, root_value):
    # 将xmind树转换为每一行的用例结构
    _case_list = []
    for topic in tree['topic']['topics']:
        parser_tree_to_list(
            root_value, topic, current_layer=1,
            pre_topics=[topic['title']], case_list=_case_list
        )
    return _case_list


def get_modules_from_xmind(xmind_file):
    xmind_tabs = xmind_to_dict(xmind_file)
    xmind_tree = xmind_tabs[0]
    root_topic_value = xmind_tree['topic']['title']
    case_list = tree_to_case_list(xmind_tree, root_topic_value)
    _modules = list(set([_[0] for _ in case_list]))
    return _modules


def get_modules_from_csv(csv_file):
    with open(csv_file, 'r', encoding='gbk') as csvfile:
        reader = csv.reader(csvfile)
        case_list = list(reader)
    _modules = list(set([_[0] for _ in case_list[1:]]))
    return _modules


def generate_case(xmind_file, save_path):
    xmind_tabs = xmind_to_dict(xmind_file)
    xmind_tree = xmind_tabs[0]
    root_topic_value = xmind_tree['topic']['title']
    # 按用例组织excel的行
    case_list = tree_to_case_list(xmind_tree, root_topic_value)
    # 生成csv格式的测试用例
    csv_case_list = [[
        "所属模块", "相关需求", "优先级", "关键词", "前置条件",
        "用例标题", "步骤", "预期", "用例类型", "适用阶段"
    ]]
    csv_case_list.extend(case_list)
    # 将用例写入csv文件
    with open(save_path, 'w', newline='', encoding='gbk') as csvfile:
        writer = csv.writer(csvfile)
        writer.writerows(csv_case_list)
        print('用例xmind已成功导出为csv文件,不包含模块id')


if __name__ == '__main__':
    xmind_file = sys.argv[1]
    target_path = xmind_file + '.csv'
    if xmind_file[-6:] == '.xmind' and os.path.exists(xmind_file):
        generate_case(xmind_file, save_path=target_path)
    elif xmind_file[-4:] == '.csv' and os.path.exists(xmind_file):
        target_path = xmind_file
        print('源文件为csv,将更新所属模块id……')
    else:
        print('用例xmind文件不存在:' + xmind_file)
        exit(0)
    if len(sys.argv) > 2:
        if len(sys.argv) < 5:
            print('同步到禅道需要额外参数:禅道项目名称 禅道账号 禅道密码')
            exit(0)
        else:
            target_product_name = sys.argv[2]
            zentao_account = sys.argv[3]
            zentao_password = sys.argv[4]
            # 创建模块
            case_modules = get_modules_from_csv(target_path)
            zentao_user = ZentaoSession()
            zentao_user.login(zentao_account, zentao_password)
            zentao_user.create_case_modules(case_modules, target_product_name)
            # 更新用例csv
            zentao_user.update_csv_case_module_id(target_path, target_product_name)
    else:
        print('只有1个参数,不进行任何禅道操作')

2、在windows+R命令窗口安装依赖

      pip install requests
      pip install xmindparser

使用pip命令时,可能会报错:

需要更新pip,执行命令:

 python -m pip install --upgrade pip

3、在xmind上编写测试用例,格式可参考:

4、将测试用例xmind与generate_case_csv_file.py文件放在同一文件夹下,在命令行进入该文件夹,执行以下命令:

            将xmind文件导出为csv文件:
            python generate_case_csv_file.py xmind文件


           将xmind文件导出为csv文件,并创建对应的禅道用例模块,同步到csv中:
            python generate_case_csv_file.py xmind文件 禅道项目名称 禅道账号 禅道密码

5、导出的csv文件需自行手动导入禅道,导入时注意检查。

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值