测试Jmeter软件

Day09_JMeter软件测试

1. 性能测试

1.1. 性能测试是什么

基于协议模拟用户发出请求,对服务器形成一定负载,来测试服务器的性能指标是否满足要求

性能指标关注点:时间性能、空间性能

性能测试与页面无关

性能测试定义:指通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行测试。

1.2. 性能测试类型

  1. 基准测试:在给系统施加较低压力时,查看系统的运行状况并记录相关数做为基础参考

  2. 负载测试:是指对系统不断地增加压力或增加一定压力下的持续时间,直到系统的某项或多项性能指标达到安全临界值,例如某种资源已经达到饱和状态等 。

  3. 压力测试:压力测试是评估系统处于或超过预期负载时系统的运行情况,关注点在于系统在峰值负载或超出最大载荷情况下的处理能力。

  4. 稳定性测试(可靠性测试):在给系统加载一定业务压力的情况下,使系统运行一段时间,以此检测系统是否稳定。24X3小时

  5. 并发测试:测试多个用户同时访问同一个应用、同一个模块或者数据记录时是否存在死锁或者其他性能问题,

1.3. 性能测试工具

image.png

2. Jmeter简介

2.1. Jmeter的基本概念

Apache JMeter是Apache组织开发的基于Java的压力测试工具。

2.2. 我们为什么使用Jmeter

开源,免费,基于Java编写,可集成到其他系统可拓展各个功能插件

支持接口测试,压力(负载和压力)测试等多种功能,支持录制回放,

入门简单相较于自己编写框架活其他开源工具,有较为完善的UI界面,便于接口调试

多平台支持,可在Linux,Windows,Mac上运行

支持多协议

2.3. Jmeter的作用

  1. 接口测试

  2. 性能测试

  3. 压力测试

  4. Web自动化测试

  5. 数据库测试

  6. JAVA程序测试

2.4. Jmeter****怎么用

Windows下Jmeter下载安装

登录 http://jmeter.apache.org/download_jmeter.cgi ,根据自己平台,下载对应文件

image.png

2.5. 安装****JAVA环境

安装JDK,配置环境变量(具体步骤不做介绍)

将下载Jmeter文件解压,打开/bin/jmeter.bat


image.png
image.png

2.6. Jmeter的目录结构

image.png

/bin 目录(常用文件介绍)

examples:目录下包含Jmeter使用实例

ApacheJMeter.jar:JMeter源码包

jmeter.bat:windows下启动文件

jmeter.sh:Linux下启动文件

jmeter.log:Jmeter运行日志文件

jmeter.properties:Jmeter配置文件

jmeter-server.bat:windows下启动负载生成器服务文件

jmeter-server:Linux下启动负载生成器文件

/docs目录——Jmeter帮助文档

/extras目录——提供了对Ant的支持文件,可也用于持续集成

/lib目录——存放Jmeter依赖的jar包,同时安装插件也放于此目录

/licenses目录——软件许可文件,不用管

/printable_docs目录——Jmeter用户手册

3. 使用Jmeter测试快速入门

3.1. 线程组是什么

进程: 一个正在执行的程序对应一个进程

线程: 一个进程有多个执行线程

线程组: 按照线程性质对线程分组

三者关系: 一个进程有多个线程组,一个线程组有多个线程

测试计划—线程组—线程组属性中的线程数

并发执行:多个线程同时执行,特点:执行结束的顺序与开始的顺序不一致

顺序执行:按照线程的启动顺序挨个执行

默认情况下,线程组中的线程是并发执行

每一个线程都要执行组内的http请求

设置线程组顺序执行:勾选测试计划中的(独立运行每个线程组)

线程组用来模拟用户的并发访问

1.1.1. 创建线程组

image.png

1.1.2. 线程组主要包含三个参数:线程数、准备时长(Ramp-Up Period(in seconds))、循环次数。

1.1.3. 线程数:虚拟用户数。一个虚拟用户占用一个进程或线程。设置多少虚拟用户数在这里也就是设置多少个线程数。

1.1.4. 准备时长(秒):设置的虚拟用户数需要多长时间全部启动。如果线程数为20 ,准备时长为10 ,那么需要10秒钟启动20个线程。也就是每秒钟启动2个线程。

1.1.5. 循环次数:每个线程发送请求的次数。如果线程数为20 ,循环次数为100 ,那么每个线程发送100次请求。总请求数为20*100=2000 。如果勾选了“永远”,那么所有线程会一直发送请求,一到选择停止运行脚本。

1.1.6. . 调度器:设置线程组启动的开始时间和结束时间(配置调度器时,需要勾选循环次数为永远)

1.1.7. 持续时间(秒):测试持续时间,会覆盖结束时间

1.1.8. 启动延迟(秒):测试延迟启动时间,会覆盖启动时间

1.1.9. 启动时间:测试启动时间,启动延迟会覆盖它。当启动时间已过,手动只需测试时当前时间也会覆盖它。

1.1.10. 结束时间:测试结束时间,持续时间会覆盖它。

image.png

3.2. 创建http请求

image.png

3.3. 指定请求域名,请求路径

image.png
image.png

3.4. 设置对应的查看内容

image.png

3.5. 查看表格信息

image.png
image.png

3.6. 查看结果树

image.png
image.png

通过察看结果树,我们可以看到每个请求的结果,其中红色的是出错的请求,绿色的为通过。

Thread Name:线程组名称

Sample Start: 启动开始时间

Load time:加载时长

Latency:等待时长

Size in bytes:发送的数据总大小

Headers size in bytes:发送数据的其余部分大小

Sample Count:发送统计

Error Count:交互错误统计

Response code:返回码

Response message:返回信息

Response headers:返回的头部信息

3.7. 聚合报告参数说明

image.png
image.png

3.8. 图形结果

image.png

样本数目:总共发送到服务器的请求数。

最新样本:代表时间的数字,是服务器响应最后一个请求的时间。

吞吐量:服务器每分钟处理的请求数。

平均值:总运行时间除以发送到服务器的请求数。

中间值:有一半的服务器响应时间低于改值而另一半高于该值。

偏离:表示服务器响应时间变化、离散程度测量值的大小。

4. Jmeter主要组件介绍

|

1.测试计划是使用 JMeter 进行测试的起点,它是其它 JMeter 测试元件的容器。

image.png

4.1. 测试计划

image.png
  1. 测试计划就是一个完整的场景

  2. “独立运行每个线程组” :勾选以后所有的线程组都是顺序执行的了。一般不勾选,让所有 的线程组并发启动。

  3. “函数测试模式” :勾选后会有详细的请求记录,消耗资源,影响客户端性能。一般不勾选。

  4. 用户定义的变量:全局变量,测试计划上可以添加用户定义的变量。一般添加一些系统常用的配置。如果测试过程中想切换环境,切换配置,一般不建议在测试计划上添加变量

image.png

4.2. 线程组

image.png

(1)、thread group(线程组)

这个就是我们通常添加运行的线程。通俗的讲一个线程组,可以看做一个虚拟用户组,线程组中的每个线程都可以理解为一个虚拟用户。

(2)、setup thread group

一种特殊类型的ThreadGroup的,可用于执行预测试操作。这些线程的行为完全像一个正常的线程组元件。不同的是,这些类型的线程执行测试前进行定期线程组的执行;类似LoadRunner的init,测试开始时进行初始化的工作。

(3)、teardown thread group

一种特殊类型的ThreadGroup的,可用于执行测试后动作。这些线程的行为完全像一个正常的线程组元件。不同的是,这些类型的线程执行测试结束后执行定期的线程组;类似LoadRunnner的end,测试结束时进行回收工作。

image.png

4.3. 取样器(Http请求)

image.png

关于http请求的的属性参数说明:

1)名称:用于标识一个sample。建议使用一个有意义的名称

2)注释:对于测试没任何影响,仅用来记录用户可读的注释信息

3)服务器名称或IP:http请求发送的目标服务器名称或者IP地址,比如http://www.baidu.com

4)端口号:目标服务器的端口号,默认值为80,可不填

5)协议:向目标服务器发送http请求时的协议,http/https,大小写不敏感,默认http

6)方法:发送http请求的方法(链接:http://www.cnblogs.com/imyalost/p/5630940.html

7)Content encoding:内容的编码方式(Content-Type=application/json;charset=utf-8)

8)路径:目标的URL路径(不包括服务器地址和端口)

9)自动重定向:如果选中该项,发出的http请求得到响应是301/302,jmeter会重定向到新的界面

10)Use keep Alive:jmeter 和目标服务器之间使用 Keep-Alive方式进行HTTP通信(默认选中)

11)Use multipart/from-data for HTTP POST :当发送HTTP POST 请求时,使用

12)Parameters、Body Data以及Files Upload的区别:

1. parameter是指函数定义中参数,而argument指的是函数调用时的实际参数

2. 简略描述为:parameter=形参(formal parameter), argument=实参(actual parameter)

3.在不很严格的情况下,现在二者可以混用,一般用argument,而parameter则比较少用

While defining method, variables passed in the method are called parameters.

当定义方法时,传递到方法中的变量称为参数.

While using those methods, values passed to those variables are called arguments.

当调用方法时,传给变量的值称为引数.(有时argument被翻译为“引数“)

4、Body Data指的是实体数据,就是请求报文里面主体实体的内容,一般我们向服务器发送请求,携带的实体主体参数,可以写入这里

5、Files Upload指的是:从HTML文件获取所有有内含的资源:被选中时,发出HTTP请求并获得响应的HTML文件内容后还对该HTML

  进行Parse 并获取HTML中包含的所有资源(图片、flash等):(默认不选中)

  如果用户只希望获取特定资源,可以在下方的Embedded URLs must match 文本框中填入需要下载的特定资源表达式,只有能匹配指定正则表达式的URL指向资源会被下载

4.4. 监听器

监听器(Listener)负责收集测试结果,同时也被告知了结果显示的方式。我们常用的包括:聚合报告、查看结果树、用表格查看结果,都支持将结果数据写入文件。其他的添加上去看看就行。聚合报告前面我们介绍过,后面是查看结果树和用表格查看结果的截图。

image.png

4.5. 逻辑控制器

image.png

4.6. 循环控制器、事务控制器

image.png

1.1.11. 循环控制器

image.png
image.png
image.png

1.1.12. 事务控制器

作用: 事务控制器会生产一个额外的采样器,用来统计该控制器子结点的所有时间。

在线程组下创建事务控制器

参数:

· Generate parent sample:(选中这个参数结果展示如下图红框,否则显示为下图蓝框)

· Include duration of timer and pre-post processors in generated sample:选中这一项会统计定时器(timer)的时间,否则只统计采样器(sample)的时间

image.png

创建sample 访问首页和注册页面

image.png

生成聚合报告

image.png

勾选

image.png

聚合报告中只有一项事务报告

image.png

4.7. 断言---检查点

断言(Assertions)可以用来判断请求响应的结果是否如用户所期望的。它可以用来隔离问题域,即在确保功能正确的前提下执行压力测试。这个限制对于有效的测试是非常有用的。

image.png
image.png
image.png

4.8. 前置处理器和后置处理器

image.png

前置处理器(Pre Processors)和后置处理器(Post Processors)负责在生成请求之前和之后完成工作。前置处理器常常用来修改请求的设置,后置处理器则常常用来处理响应的数据。我们主要在动态关联中用到后置处理器的正则表达式提取器。

https://www.cnblogs.com/fengpingfan/p/4755411.html

4.9. 定时器

定时器(Timer)负责定义请求之间的延迟间隔

image.png
image.png

5. Jmeter组件参数化

5.1. 参数化是什么

动态的获取并设置数据

5.2. 为什么使用参数化

执行批量操作,批量添加批量删除,人工效率太低

运用程序代替人工获取并设置数据,安全高效

比如:对被测系统的用户名和密码进行参数化,来模拟多个用户同时登录系统

5.3. 参数化实现之CSV Data Set Config

通过这个组件可以动态获取并设置数据,实现批量添加操作

image.png
image.png
image.png

Filename:所需数据文件的路径。如和脚本同一路径,可直接填写文件名

File encoding:编码和文件保持一致即可,默认为ANSI。如有中文,建议为UTF-8

Variable Names:引用变量时的变量名,对应数据文件中的每一列,以逗号分隔。如不填写,文件的第一行数据将被读取为变量名

Delimiter:在.txt、.dat文件中,可以用逗号(,)或者Tab键(\t)来区分列与列

Allow quote data:选项选为“true”的时候对全角字符的处理出现乱码

Recycle on EOF:到数据文件结尾时是否循环读取。设置为True时,线程数过多,数据文件读取到最后一行时,会再次从第一行开始读取。设置为False,到达文件结尾时如继续读取,则值会默认为<EOF>,可通过设置jmeter属性csvdataset.eofstring来改变该值。

Stop thread on EOF:Recycle on EOF设置为False,Stop thread on EOF设置为True,则读取数据文件最后一行后,停止测试,不管还有多少线程组未执行。

Sharing mode:共享模式。默认在所有线程组中使用,可选择每个线程组单独打开

image.png

查看结果树

image.png

5.4. 、使用Jmeter函数助手:

1、点击 选项-->函数助手 调出函数助手对话框

2、选择 _CSVRead 函数(下图第一个框)

3、函数参数:

1)第一个参数:填写文件路径。

2)第二个参数:文件列号是从0开始的,第一列0、第二列1、第三列2、依次类推,然后点击【生成】按钮,则会自动生成我们需要的参数化函数。

  1. 复制生成的参数化函数, copy过程需要使用的地方即可。

  2. _Random函数是从某数据段随机读取数据替换参数,当需要添加多条数据记录且某些字段需要唯一性时使用。

image.png

6. Jmeter脚本录制

6.1. 什么是脚本录制

在进行测试的时候,可能有好多脚本或者界面需要操作测试,并且有些测试链接需要重复多线程高并发进行测试,我们一般会针对这一些操作,进行一个脚本录制,录制好之后,之后测试就可以在这个基础上进行测试。

6.2. Jemeter脚本录制方式

BadBoy脚本录制

使用Jmeter自带的代理服务器进行脚本录制

7. 使用Jmeter自带的代理服务器进行脚本录制

7.1. 在测试计划上创建线程组

image.png

7.2. 添加录制控制器

image.png

7.3. 在工作台上添加http代理服务器

image.png

7.4. 配置Http代理服务器

image.png

7.5. 配置浏览器

1.1.13. Google浏览器

image.png
image.png
image.png

1.1.14. 火狐浏览器

image.png
image.png

7.6. 浏览器请求测试

image.png

7.7. 过滤信息

添加如下内容

..js.|..css.|..png.|..jpg.|..gif.|..bmp.

image.png
image.png

8. Android手机端脚本录制

8.1. 查看电脑IP

image.png

8.2. 配置手机网路连接

image.png
image.png

8.3. 手机访问app

image.png
image.png

8.4. 模拟登陆操作

image.png
image.png

8.5. 执行结束之后,停止脚本录制

image.png

8.6. 脚本测试-线程组设置10个线程分别请求10次

image.png

8.7. 查看结果树

image.png

9. BadBoy脚本录制

9.1. 安装badboy脚本软件

image.png

傻瓜式安装即可

9.2. 打开badboy软件

image.png

9.3. badboy脚本录制

点击录制按钮进行脚本录制,完成打开搜狗搜索,搜索测试岗位薪资操作,然后停止,回放,(回放的时候,会因为编码原因导致乱码,需要手动调乱码问题)

image.png
image.png
image.png
image.png

9.4. 添加验证点

验证点的作用就是验证脚本是否按照我们测试的思路执行,判断脚本执行过程中是否存现问题

image.png

9.5. badboy参数化

所谓参数化,是指请求的某个参数提前设定多个值,在具体请求的时候,去获取提前设定的值,不同的业务场景设置的参数不一致。

image.png
image.png
image.png
image.png
image.png

9.6. 导出Jmeter脚本

image.png

9.7. 在Jmeter中导入badboy生成的脚本,验证测试

image.png

9.8. badboy并发测试

选择tools run background

image.png

9.9. badboy测试报告

在badboy-->view--->report下可以看到测试报告

[图片上传失败...(image-ea070b-1603883592481)]

10. Jmeter扩展插件-显示内存效果图

Jmeter本身是不能够展示内存,cpu和吞吐量的,但是可以通过添加插件的方式来对jmeter添加这些功能

<u>https://www.cnblogs.com/imyalost/p/7751981.html</u>

<u>JMeter之ServerAgent监控资源</u>

image.png

10.1. 对linux服务器的服务进行压测

时,服务器的运行情况可以通过添加插件来观察,而不用使用top命令实时的去看

1、资源准备

2、环境准备

3、资源监控

1、资源准备

可通过该网址下载jmeter所有插件http://jmeter-plugins.org/downloads/all/

万能的网盘:

本次所需插件:

JMeterPlugins-Extras.jar

JMeterPlugins-Standard.jar

ServerAgent-2.2.1

将JMeterPlugins-Extras.jar和JMeterPlugins-Standard.jar放到apache-jmeter-3.0\lib\ext目录下

将ServerAgent-2.2.1放到linux服务器opt目录下

2、环境准备

ServerAgent服务端口号默认为4444,需要设置防火墙对此端口不拦截:

vi /etc/sysconfig/iptables,在端口22下面添加 iptables -I INPUT -p tcp --dport 4444 -j ACCEPT //允许4444端口访问

然后在服务器中启动监控服务:

image.png

使用以下命令可以改变默认的4444端口

<u>java</u> -jar ./CMDRunner.jar --tool PerfMonAgent --udp-port 7777 --tcp-port 7777

同样的,7777端口也要设置防火墙规则以及使用telnet本地测试下是否可以访问

10.2. windows****本机进行监听

image.png
image.png
image.png

先在服务器上开启server的监听

image.png

开始演示效果

jp@gc - Bytes Throughput Over Time:不同时间吞吐量(字节Bytes)展示(图表)

聚合报告里,Throughput是按请求个数来展示的,比如说1.9/sec,就是每s发送1.9个请求;而这里的展示是按字节Bytes来展示的图表,表示每秒发送多少字节

image.png

jp@gc - Hits per Second:每秒点击量,点击量在性能测试-常见的性能指标(一)的博文中已经详细介绍,指的是每秒web服务器接收到的请求数

image.png
image.png
image.png
image.png

jp@gc - PerfMon Metrics Collector:服务器性能监测控件,包括CPU,Memory,Network,I/O等等(此功能用到在需监听的服务器上启动startAgent)

根据需要选择CPU,Memory,Network I/O等

image.png
image.png

11. Jmeter数据库压力测试

11.1. 先配置jdbc(数据库连接)驱动

1、启动jmeter,打开界面工具,添加一个线程组,添加驱动

image.png

2、添加一个JDBC Connection Configuration,连接池配置文件。右键线程组【添加】--【配置元件】--【JDBC Connection Configuration】

image.png
image.png

Variable Name:连接池名称。JDBC Request会通过此名称来获取连接池的配置,名称可以随意填写,但是最好具体实际的业务意义,方便理解和记忆。

其他的可以默认,可以根据实际情况来调节优化性能。

Database URL:数据链接url,格式:jdbc:mysql://localhost:3306/host

注释:数据库的ip地址+端口/数据库名(查询数据库端口号show global variables like 'port')

JDBC Driver Class:驱动器名称。固定:com.mysql.jdbc.Driver

Username:用户名

Passowrd:密码

添加一个JDBC Request。

3、右键线程组【添加】-【Sampler】-【JDBC Request】

image.png

Select Statement:查询语句

Updata Statement:更新语句

Prepared Select Statement:预编译查询语句。(长时间执行效率更高,支持占位符)

Prepared Update Statement:预编译更新语句。(同上)

Commit (立即提交)Rollback(回滚)

image.png

Parameter values:参数值。参数化sql语句中的值。故输入:localhost,root

Paramter types:参数类型。数据库的参数你可以去查看一下。这里是两个CHAR,CHAR类型。

Variable names:变量名字,也就是将筛选出来的值放在变量里面。例如这三列数据分为放在变量:A,B,C中(实际操作中命名一定要有实际意义)。

Result variable name:存储变量名。将整个结果存储在变量中。取名:rs

Query timeouts :超时时间。

12. Jmeter正则表达式提取

12.1. badboy录制脚本

image.png

12.2. 将脚本导出到jmeter

image.png

12.3. 回放时候失败-session过期

12.4. 查看返回信息,查找userSession

image.png

12.5. 使用正则提取

运用Jmeter正则提取器,可以从请求的响应结果中取到需要的内容,从而实现关联。关联是请求与请求之间存在数据依赖关系,需要从上一个请求获取下一个请求需要回传回去的数据

位置****1:名称及注释

正则表达式(regular expression)描述了一种字符串匹配的模式(pattern),可以用来检查一个串是否含有某种子串、将匹配的子串替换或者从某个串中取出符合某个条件的子串等。

image.png

构造正则表达式的方法和创建数学表达式的方法一样。也就是用多种元字符与运算符可以将小的表达式结合在一起来创建更大的表达式。正则表达式的组件可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件的任意组合。

位置2:正则表达式提取的相关设置

image.png

说明:

(1)引用名称:下一个请求要引用的参数名称,如填写title,则可用${title}引用它。

(2)正则表达式:

():括起来的部分就是要提取的。

.:匹配任何字符串。

+:一次或多次。

?:不要太贪婪,在找到第一个匹配项后停止。

(3)模板:用引用起来,如果在正则表达式中有多个正则表达式,则可以是$23等等,表示解析到的第几个值给title。如:1$表示解析到的第1个值

(4)匹配数字:0代表随机取值,1代表全部取值,通常情况下填0

(5)缺省值:如果参数没有取得到值,那默认给一个值让它取。

12.6. 使用参数化

image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270