接口测试 在云服务器上部署 Django 项目用来做接口测试和性能测试

追风 · 2023年01月03日 · 3917 次阅读

我们做为测试工程师,除了日常的工作外,有时候也想要提高自己。但是以我自己为例,几年前工作中大部分时间接触的都是 windows 下的应用程序的测试。针对这类应用程序的测试,除了功能测试之外,也会执行自动化测试。这类自动化测试由于不是基于 web 的项目所以不会用到 selenium 等 web 框架。大部分情况下都是公司自研的,或者是一些收费软件用来做自动化测试。从这个角度看,相对来说技术的提升面会略微有所狭窄,即便是你打算在一家公司干到退休,如果是单纯的走技术路线,可能后期也会因为平时工作中接触的技术太过单一而越发的困难。如果你想去外面看机会,就会发现你在现在的公司还被当成中流砥柱,但是去别的地方面试就感觉自己总是差了一截。这一截,并不是说差在你的测试思维,你的自动化思维不行,而是单纯的技术栈不匹配,相信有过同样经历的小伙伴们都懂。所以这推动着我丰富自己的技术栈,提升自己的技术。当然,技术路线的提升有很多种,比方你可以自研平台、去做 CI/CD 等等。这里给大家提供另外一个思路,通过自我学习的方式一方面去保持自己对技术的敏感性,另一方面也是给自己寻找另外一种可能。

前段时间在腾讯云上租了一个 2G4 核的轻量应用服务器,因为是新人的原因,所以一年的话也只要 100 多。搭配上云硬盘也就 200,但是记得要提前和客服沟通好云硬盘搭载的区域,否则你就会像我一样买了又退,哈哈。租云服务器的初衷,是想找一个现成的开源项目然后直接部署上去,相当于有了一个自己的网站可以用来做 web UI 自动化测试,接口测试,性能测试。但是翻遍了 github,不管是基于 java,python,还是 go,好的项目有很多,但是实施起来会发现有的项目部署并不友好,有的项目你想要部署上去,还要对代码逻辑有一定的了解,有些则过于花哨。目标导向就会发现,你前期会做很多的无用功,无疑对于现在的我有些浪费时间。所以就有了这个项目。

这个项目当前在 github 开源,大家可以访问这个路径来获取源码,欢迎大家提需求,后期可能都会添加。访问地址:https://github.com/CactusStar/DemoDjango

这个项目到目前,没有做任何的 UI 层面的美化,提供的功能也很单一:用户登录,数据的增删改查,文件下载,文件上传。下面我们言归正传,聊聊这个项目的实现。

首先这是一个基于 django 的项目,对于技术的选型,其实没有什么心路历程。我对于 java,python,go 这三门语言的 web 框架都有过一些了解,不同的目的和场景这三种语言和框架各有优势,为了后面做性能测试引进 locust 这个工具,所以选了 Python 作为开发语言,之前用过 flask 所以这次想试试 django。

如果你像我一样想自己去开发一个 django 的项目,那么我建议你去找一个入门教程看一下,对着敲一下代码,熟悉一下 django 的风格。我看的菜鸟教程,写的浅显易懂,就是版本有些低了,不过也还好,没有特别大的差别。

项目创建和.py 文件的作用

Django 的安装这里就不说了,直接 pip install 即可,再执行如下的命令还创建一个项目:

django-admin startproject demo

项目创建成功之后,我们主要需要做的和关注的事情如下

  • 创建 templates 文件夹,用来存放 html 文件
  • demo 下的init.py 文件,用来输入以下代码,注:因为我的数据库使用的是 mysql,所以这里我导入的库是 pymysql,对应的也是 mysql 相关的方法
import pymysql

pymysql.install_as_MySQLdb()
  • models.py,简单的解释是用来定义数据库表的名字,列的属性的一个文件。这里由于 django 框架本身的处理比较多,我们作为 django 的用户直接以类的形式定义这个表和列的属性,相对来说会很简单,不太方便的地方就是可能你需要提前了解一下都有哪些方法,但是我觉得这就是框架的优势和劣势吧,毕竟没有完美的事情。
class Book(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32) 
    price = models.DecimalField(max_digits=10, decimal_places=2) 
    publish = models.CharField(max_length=32) 
  • settings.py,顾名思义,这个文件是用来做配置的
  • urls.py,这个文件是用来定义路由的,即访问哪个路径时要访问哪个方法
  • views.py,这个文件自己是自己创建的,你可以根据你的需要创建多个,根据不同的功能命名,用来存放路由方法

执行如下命令即可在 settings.py 中配置的数据库中创建 django 自带的一些表以及用户自定义的表

python manage.py migrate
python manage.py makemigrations

功能实现

上文提到过,demo 项目只实现了简单的用户登录,数据的增删改查,文件下载,文件上传的功能

用户登录

django 自带用户的创建功能,他提供了一张 user 表以及相应的用户创建、用户校验的方法
create_user():创建用户,密码加密
create(): 创建用户,密码明文
可自行创建用户进行测试

实现代码如下

def login_auth(request):
    if request.method == 'POST':
        username = request.POST['username'] # 表单的值
        password = request.POST['password'] # 表单的值
        print(username)
        user = authenticate(request, username=username, password=password) # 用户校验
        if user is not None:
            login(request, user)  # 保存登录会话,将登陆的信息封装到request.user,包括session
            return redirect("/index")
        else:
            return render(request, 'login.html', {'error': '用户名或密码错误!'})
    return render(request, 'login.html')

对应的 html 文件

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>DEMO</title>
</head>
<body>
    <form action="" method="post">
        {% csrf_token %}
        <p>username: <input type="text" name="username"></p>
        <p>password: <input type="password" name="password"></p>
        <input type="submit" name="submit">
        {% if error %}
         <p style="color: red;">{{ error }}</p>
        {% endif %}
    </form>

</body>
</html>

数据的增删改查

django 使用 ORM 的方式进行数据库的操作,简单来说 ORM 就是封装了对数据库操作的 sql。好处是,在框架支持的数据库范围内,不管是什么数据库写法都一样。劣势是,用户需要熟悉这些方法,同时对 sql 的敏感性会下降。

以插入数据为例,代码如下

@login_required
def insert_data(request):
    # 需要全部字段来插入一条数据
    if request.method == 'POST':
        title = request.POST["title"]
        price = request.POST["price"]
        publish = request.POST["publish"]
        models.Book.objects.create(title=title, price=price, publish=publish)
        return render(request, 'insert.html', {'message':'insert successfully'})
    return render(request, 'insert.html')

这段代码中,装饰器@login_required表明这个方法需要先登录才能调用。这是 django 提供给我们的便利,直接使用即可
create() 是对数据库的插入操作,相当于 sql 中的 INSERT

文件的下载

文件的下载。我对于文件的下载,拷贝等等的理解,在不同的语言中,不管是通过 stream 的方式还是其他的方式,本质上都是创建一个文件然后对他进行写入。django 中,我们有多种方法可以使用,这个项目中使用的是 StreamingHttpResponse 的方法。代码如下

@login_required
def download_big_file(request):
    file_path = "/project/resource/big.jpg"
    try:
        r = StreamingHttpResponse(open(file_path, "rb"))
        r["content_type"] = "application/octet-stream"
        r["Content-Disposition"] = "attachment;filename=big.jpg"
        return r
    except Exception:
        raise Http404("Download error")

文件的上传

文件的上传其实和下载在原理上并没有什么特别大的出入,下载是从服务器上拿资源,上传是从本地向服务器发送资源。代码如下

@login_required
def upload_file(request):
    if request.method == 'POST':
        File = request.FILES.get("myfile", None)
        if File is None:
            return HttpResponse("No upload file needed")
        else:
            with open("/project/upload/%s" % File.name, 'wb+') as f:
                for chunk in File.chunks():
                    f.write(chunk)
            return render(request, 'upload.html', {'message':'upload successfully'})
    return render(request, 'upload.html')

upload.html

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>DEMO</title>
</head>
<body>
    <div>
        <form action="" method="post" enctype="multipart/form-data">
            {% csrf_token %}
            <p>filename:<input type="file" name="myfile"/></p>
            <input type="submit" value="upload"/>

        </form>
        {% if message %}
        <p style="color: green;">{{ message }}</p>
        {% endif %}
    </div>
</body>
</html>

功能到这里就实现完毕了,其实我们可以看出来,代码本身并不复杂,有很多功能 django 已经替我们实现了,这就是使用框架的好处了。这个项目本地跑起来,最终的样子就会是有一个主页,主页上有几个 link,点击 link 会跳转到不同的功能页面,很难看,很简单,哈哈。

部署

功能实现了,我们就要着手部署了。这里我们部署的服务器是 Linux 的 Centos 的系统。因为我的项目是在 python3.10.7 这个版本进行的开发,所以,为了在安装一些依赖库的时候版本可以正常匹配,我们最好在服务器上安装对应的 Python 版本。我这台服务器上本身带有 python2.7.5 和 python3.6.5,保险起见我还是进行了升级。数据库用的是 mysql 的 8.0 及以上的版本。

安装 mysql

这里直接搬运其他人的成果啦
https://blog.csdn.net/u010881625/article/details/126401832
我选择的 yum 安装,只要逐步按照上述链接来,就会成功安装。记得安装成功后创建你的项目需要的数据库以及设置密码,以和项目中的配置保持一致。

安装 python3.10

说实话,安装 python3.10 的过程很恶心,强烈建议各个云厂商可以让用户自己做出在创建这个服务器的时候除了提供的基础配置外还需要哪些配置,一次性安装。

首先,要安装 python3.10 并能正常使用 pip 能功能,需要升级 openssl 到 1.1.1 的版本,这里我用的是以下方法,亲测好用
https://blog.csdn.net/bai920708/article/details/127658888?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22127658888%22%2C%22source%22%3A%22bai920708%22%7D

安装 python3.10 用的是下面的步骤,请自行取用
https://blog.csdn.net/bai920708/article/details/127659568

安装 uwsgi,直接通过 pip 安装,安装之后建立软连接

ln -s /usr/local/python3/bin/uwsgi /usr/bin/uwsgi

安装 nginx
https://blog.csdn.net/qq_32702685/article/details/125313528

到此,运行项目所需要的前置步骤环境准备都已经完成。

下面在我们的程序目录下,运行 pip freeze > requirements.txt,然后将程序打包,拷贝到服务器上解压。
我并没有创建虚拟环境来运行这个项目,原因是我在之前的项目中使用过虚拟环境,当时我的运行环境为 windows,不知道是我自己的配置问题还是其他问题,虚拟环境虽然可以让开发环境隔离的很好,并且随用随拿,但是在项目运行的时候总会出现一些奇奇怪怪的问题,所以为了节省时间我直接进行了部署。后续有时间会重新用虚拟环境部署一下,仔细查明问题到底在哪。

项目解压之后还需要做一些事

配置 uwsgi 文件

在项目根目录下创建 项目名称.xml,把以下内容拷贝进去

<uwsgi>
   <socket>127.0.0.1:8000</socket><!-- 内部端口,自定义 -->
   <chdir>/project/Demo/demo</chdir><!-- 项目路径 -->
   <module>demo.wsgi</module><!-- wsgi.py所在目录名-->
   <processes>4</processes><!-- 进程数 -->
   <daemonize>uwsgi.log</daemonize><!-- 日志文件 -->
</uwsgi>

配置 Nginx

在 Nginx 的配置文件中,将 server 部分替换成下面

server {
    listen 80;
    server_name  127.0.0.1:80; #改为自己的域名,没域名修改为127.0.0.1:80
    charset utf-8;
    location / {
       include uwsgi_params;
       uwsgi_pass 127.0.0.1:8000;  #端口要和uwsgi里配置的一样
       uwsgi_param UWSGI_SCRIPT demo.wsgi;  #wsgi.py所在的目录名+.wsgi
       uwsgi_param UWSGI_CHDIR /project/Demo/demo; #项目路径

    }
}

运行 Nginx,访问你的服务器 ip。

到此,整个程序就已经部署在服务器上了。

项目很简单,接下来会根据需要丰富其他的功能以能满足测试的需要。下一步,会写一些性能测试代码和接口测试代码,然后用 grafana 来进行数据展示。同时也会做 CI 相关的功能,实现自动执行自动化测试并上传保存结果。后续也会和大家分享实际项目中用到的基于 docker, github action 相关的技术。欢迎大家关注。

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册