跳到主要内容

关于覆盖率测试的概念

· 阅读需 3 分钟

测试覆盖率

代码覆盖(Code coverage)是软件测试中的一种度量,描述程式中源代码被测试的比例和程度,所得比例称为代码覆盖率。

指标

以下是几个覆盖率指标:

  • 函数覆盖率(Function coverage):调用到程式中的每一个Function吗?
  • 行覆盖率(Line coverage):执行到程序中的每一行了吗?
  • 语句覆盖率(Statement coverage):若用控制流图表示程序,执行到控制流图中的每一个节点了吗?
  • 分支覆盖率(Branches coverage):若用控制流图表示程式,执行到控制流图中的每一条边吗?例如控制结构中所有IF指令都有执行到逻辑运算式成立及不成立的情形吗?
  • 条件覆盖率(Condition coverage):也称为谓词覆盖(predicate coverage),每一个逻辑运算式中的每一个条件(无法再分解的逻辑运算式)是否都有执行到成立及不成立的情形吗?

对指标的偏好可说是见仁见智,比如大名鼎鼎的 coveralls.io 就以行覆盖率(Line coverage) 作为给项目颁发badge的首选指标。

node.js单元测试之带session和cookie的案例

· 阅读需 5 分钟

需要cookie和session的测试案例

在web开发中,Cookie有着非常重要的作用。因为HTTP是无状态的,所以需要用cookie来辅助实现用户认证。我们先来简单介绍一下cookie的工作机制。

untitled1.png

如果所示,如果通过cookie和session协同识别一个用户需要两次请求,第一次请求的时候,服务器并不认识你,但是他给你标记了一个他独有的id,等到第二次请求的时候,浏览器自动给你带上了之前的标签,这样服务器就知道你之前请求过了。

那么问题来了,如果我们写测试案例的时候,需要两次请求来实现的话,会非常麻烦,测试案例也会很冗长。怎么才能一次请求就能使用cookie和session呢?

这时候express的中间件的好处就体现了。 首先,我们在用supertest进行HTTP请求的时候,可以通过下面的形式设置cookie:

set('Cookie', cookieValue)

然后,我们写一个非常简单的中间件:

app.use(function(req, res, next) {
if (config.debug && req.cookies['mock_user']) {
var mockUser = JSON.parse(req.cookies['mock_user']);
req.session.user = new UserModel(mockUser);
return next();
}
next();
});

原理就是先判断当前是否为开发环境,通过config来设置,通常在开发阶段这个值设置为true。其次判断是否具有键为mock_user的cookie键值对,如果存在,设置session里面的user值,这样,只要一次请求我们就能实现用户标识。 最后要解决的问题就是怎么设置字段键为mock_user的cookie了,具体的用法可参照test目录里面的support/support.js,这里不多说。


补充

测试时加上

.set('Cookie', cookie)

那么这个cookie是什么形式呢?

Cookie: mock_user=xxxxxxxxxx

var cookie = [ 'mock_user', encodeURIComponent(JSON.stringify(support.user))].join('=');

mysql 创建用户及授权命令操作

· 阅读需 3 分钟

命令: CREATE USER 'username'@'host' IDENTIFIED BY 'password';

说明: username - 你将创建的用户名, host - 指定该用户在哪个主机上可以登陆,如果是本地用户可用localhost, 如果想让该用户可以从任意远程主机登陆,可以使用通配符%. password - 该用户的登陆密码,密码可以为空,如果为空则该用户可以不需要密码登陆服务器.

例子:

CREATE USER 'dog'@'localhost' IDENTIFIED BY '123456';
CREATE USER 'pig'@'192.168.1.101_' IDENDIFIED BY '123456';
CREATE USER 'pig'@'%' IDENTIFIED BY '123456';
CREATE USER 'pig'@'%' IDENTIFIED BY '';
CREATE USER 'pig'@'%';

授权

命令: GRANT privileges ON databasename.tablename TO 'username'@'host'

说明: privileges - 用户的操作权限,如SELECT , INSERT , UPDATE 等(详细列表见该文最后面).如果要授予所的权限则使用ALL.; databasename - 数据库名,tablename-表名,如果要授予该用户对所有数据库和表的相应操作权限则可用表示, 如.*.

例子:

GRANT SELECT, INSERT ON test.user TO 'pig'@'%';
GRANT ALL ON *.* TO 'pig'@'%';

注意:用以上命令授权的用户不能给其它用户授权,如果想让该用户可以授权,用以下命令:

GRANT privileges ON databasename.tablename TO 'username'@'host' WITH GRANT OPTION;

node.js 判断当前模块是否是程序的入口

· 阅读需 1 分钟

看别人写的node.js代码的时候,看到有很多地方会有这么一个写法。

// start the server if `$ node server.js`
if (require.main === module) {
//to do something
}

其实这就是判断当前模块是否是程序的入口。

nodejs 集成支付宝所遇到的坑

· 阅读需 3 分钟

首先,使用express框架,能够接收到支付宝发来的POST notify请求,但是解析出来的body一直为空对象,然后将整个请求log出来查看,发现支付宝发来的Content-Type是一个奇葩的

application/x-www-form-urlencoded;text/html;charset=utf-8

这TM什么鬼玩意,到底是form还是html,于是bodyParser就扑街表示不认识了

解决方式也非常简单暴力,在bodyParser中间件之前添加一个中间件

app.use(function (req, res, next) {
if (req.url == '/alipay' || req.url == '/alipay/test'){
req.headers['content-type'] = 'application/x-www-form-urlencoded';
}
next();
});

其次是校验notify的签名时,支付宝官方给的说明是这样的 untitled1.png

如果没注意仔细看的话,就会以为是queryString的方式拼接,于是我用了nodejs自带的query-string库,做好了queryString.stringify(),一切完美。但是签名校验根本过不去

后来突然想到,难道不要urlencode,不是queryString,于是把代码替换成了手工拼接字符串而不要urlencode。校验就过去了……

原文 https://blog.bangbang93.com/2015/12/08/nodejs%E9%9B%86%E6%88%90%E6%94%AF%E4%BB%98%E5%AE%9D%E6%89%80%E9%81%87%E5%88%B0%E7%9A%84%E5%9D%91.moe?utm_source=tuicool&utm_medium=referral

微信爬虫的cookie池的node.js实现

· 阅读需 2 分钟

之前的一篇文章说到了维护一个cookie池来降低500的概率。

记搜狗微信号搜索反爬虫

在知乎上看到有人说只需要SNUID替换,其他的不影响。 所以我就写了一个SNUID的池,存储在redis中。

思路:

  1. 通过随机关键字不带cookie请求weixin.sogou.com
  2. 从请求的header中抽取SNUID缓存在redis中。
  3. 每6个小时将SNUID池更新一遍。

代码在这里: https://github.com/luoyjx/weixin-crawler-es5

记搜狗微信号搜索反爬虫

· 阅读需 6 分钟

反爬虫

RSS Factory前段时间又出问题了,访问微信公众号RSS一直500,完全没法用了。 经调试,发现由于爬取数据太频繁,触发了搜狗微信公众号的反爬虫,探索了下反爬虫的规则:

没有带Cookie的情况下,频繁访问触发反爬虫

  • 带Cookie的情况下,频繁访问偶尔触发反爬出,偶现500错误
  • 不带Cookie情况下,隔几个小时范围一下不会触发反爬虫
  • Cookie有几个关键字段用于识别爬虫,SUID,SNUID,SUV。 不带Cookie请求任意搜狗微信公众号页面,应答set-cookie会带SUID,SNUID字段,SUV由JavaScript生成。

应对反爬虫

基于以上探索的反爬虫措施,制定应对反爬虫的策略。

  • 维护一个Cookie池
  • 爬取数据时随机取Cookie
  • 定时更新Cookies池

实现

@tornado.gen.coroutine
def get_cookies():
cookies = []
client = tornado.httpclient.AsyncHTTPClient()
for i in xrange(10):

url = 'http://weixin.sogou.com/weixin?query=%s' % random.choice('abcdefghijklmnopqrstuvwxyz')

# 获取 SNUID
cookie_request = tornado.httpclient.HTTPRequest(url=url, method='HEAD')
cookie = yield client.fetch(cookie_request)
SUID = re.findall(r'(SUID=\S+?);', cookie.headers['set-cookie'])[0]
m = re.findall(r'(SNUID=\S+?);', cookie.headers['set-cookie'])
if m:
SNUID = m[0]
headers = {'Cookie:': '; '.join([SUID, getSUV(), SNUID])}
cookies.append(headers)

mc = memcache.Client(['%s:15211' % IP])

if cookies:
mc.set('cookie', cookies)

用到了tornado的协程,使用异步httpClient,发送请求时使用HEAD方法,只请求头部,通过解析set-cookie生成自己的Cookie头,连续不带Cookies访问1-次,生成Cookie池,并且保存在memcached中。

在调用tornado.ioloop.IOLoop.instance().start()之前,调用get_cookies(),任务就能正常运行了,但是我们需要定时更新Cookie池,所以还要添加定时任务。

tornado有两种方式可以定时运行可调用对象:

# 延时运行,接受 delta 延时时间间隔为 datetime.delta 对象,func 为可调用对象,但是只能调用一次,所以如果用 add_timeout 还需要在 func 中显式的再 add_timeout 才能实现定时调用
tornado.ioloop.IOLoop.instance().add_timeout(delta, func)

# 定时回调,以毫秒为单位,每 6 个小时调用一次
tornado.ioloop.PeriodicCallback(get_cookies, 6*60*60*1000).start()

效果

实现了定时任务后每6个小时会更新一次Cookie池,产生10个新的Cookie,爬取数据时使用随机Cookie明显降低了产生500的概率,效果良好。

欢迎使用RSS Factory。

将 mongodb 安装为 windows 服务

· 阅读需 1 分钟

将mongodb安装为windows服务。

cmd中cd到mongodb的bin目录下,执行以下指令

mongod
--install
--serviceName MongoDB
--serviceDisplayName MongoDB
--logpath D:\MongoDB\logs\MongoDB.log
--dbpath D:\MongoDB\data
--directoryperdb
--journal
--storageEngine=mmapv1

支付宝和微信支付一点感想(9.18更新)

· 阅读需 5 分钟

两边肯定是都有开发文档的,只要签约了之后都会拿到相应的秘钥之类的。

感觉把,支付宝的文档还是比较详细的,而且他们做的事不用说还是比较多的。

举例,支付宝的可以点击按钮跳过去付款再用你给的return_url跳到你的系统过去,或者是加个参数,变成扫码支付,扫完之后付款然后再跳转页面,可以说基本你按他的文档把参数拼接好了之后基本不需要多操心了,而且回调也是query parameter的方式,比较好解析。

微信,我用的扫码支付二(这种扫码直接支付的),感觉挺麻烦的。 首先,交互采用的xml的方式,对于node.js来说不是很友好,发送的时候要拼接一次,接收的时候要解析一次,而且,只是返回一个地址,还要自己生成二维码,扫了之后也没有后续操作了。

我看那个扫码支付模式一台麻烦就没弄,有时间再看看。

唉,不过没办法,两种都要接。


9.18

相当坑,微信支付的notify_url也就是异步的通知接口,必须你这边的地址是走https协议的,所以我放弃了。

只能在微信支付的页面的跳转按钮做手脚了,大致步骤如下:

  1. 扫码后,点击跳转到我的订单,实际上我在中间加了一层
  2. 通过查询接口去查询订单的情况,根据结果来更新你的订单信息
  3. 再跳转到订单列表去

暂时没想到更好的解决方案了,看到过别人有说轮训,对我来说好像不大好实现