2016.4 至今:开源图表库 ECharts @百度
2009-2016:本科+硕士 @上海交通大学 软件学院,数字艺术媒体实验室
更多作品参见 github.com/Ovilia
// QUnit
test("pow(2, 2) should return 4", function(){
equal(math.pow(2, 2), 4, "result was " + result);
});
test("pow(2, 3) should return 8", function(){
equal(math.pow(2, 3), 8, "result was " + result);
});
// Jasmine
describe("pow", function(){
it("should raise 2 to the power of 2", function(){
expect(math.pow(2, 2)).toBe(4);
});
it("should raise 2 to the power of 3", function(){
expect(math.pow(2, 3)).toBe(8);
});
});
// Mocha
var expect = require('chai').expect;
describe("pow", function(){
it("should raise 2 to the power of 2", function(){
expect(math.pow(2, 2)).to.equal(4);
});
it("should raise 2 to the power of 3", function(){
expect(math.pow(2, 3)).to.equal(8);
});
});
自动化测试浏览器相关操作
module.exports = {
'Demo test Google' : function (client) {
client
.url('http://www.google.com')
.waitForElementVisible('body', 1000)
.assert.title('Google')
.assert.visible('input[type=text]')
.setValue('input[type=text]', 'rembrandt van rijn')
.waitForElementVisible('button[name=btnG]', 1000)
.click('button[name=btnG]')
.pause(1000)
.assert.containsText('ol#rso li:first-child',
'Rembrandt - Wikipedia')
.end();
}
};
可使用 Nightwatch.js 这类库测试 DOM 结构
toDataURL()
保存成图片
Jasmine 单元测试
例:线性数据管理模块 List
describe('List', function () {
var testCase = window.utHelper.prepare(['echarts/data/List']);
describe('Data Manipulation', function () {
testCase('initData 1d', function (List) {
var list = new List(['x', 'y']);
list.initData([10, 20, 30]);
expect(list.get('x', 0)).toEqual(10);
expect(list.get('x', 1)).toEqual(20);
expect(list.get('x', 2)).toEqual(30);
expect(list.get('y', 1)).toEqual(20);
});
// ...
});
});
如何测试渲染相关部分?
例:配置项 title.text
允许 \n
表示换行
chart.setOption({
series: [],
title: {
text: 'first line\nsecond line'
}
});
如何测试?
canvas.toDataURL()
比较 Canvas 图像是否一致操作更简单,不依赖第三方库
更严格的测试,发现潜在错误
Canvas 1 | Canvas 2 | Canvas Diff |
normal
var testCase = {
name: 'should display bold font weight',
option1: {
series: [],
title: {
text: 'bold font vs. normal font',
textStyle: {
}
}
},
option2: {
series: [],
title: {
text: 'bold font vs. normal font',
textStyle: {
fontStyle: 'normal'
}
}
}
};
var optionCompare = function(isExpectEqual, title, option1, option2) {
it(title, function(done) {
require(['newEcharts'], function (ec) {
var canvas1 = helper.getRenderedCanvas(ec, option1);
var canvas2 = helper.getRenderedCanvas(ec, option2);
// canvas context and images
var ctx1 = canvas1.getContext('2d');
var ctx2 = canvas2.getContext('2d');
var img1 = canvas1.toDataURL();
var img2 = canvas2.toDataURL();
// compare canvas content or operation stack
var compare1 = compare2 = null;
if (STRATEGY === 'content') {
compare1 = img1;
compare2 = img2;
} else if (STRATEGY === 'stack') {
compare1 = ctx1.hash();
compare2 = ctx2.hash();
}
// expect to equal, or not
if (isExpectEqual) {
expect(compare1).toEqual(compare2);
} else {
expect(compare1).not.toEqual(compare2);
}
done();
});
});
};
optionCompare(true, testCase.name, testCase.option1, testCase.option2);
测试结果表明:两种配置的 Canvas 内容是一致的,而操作是不一致的。
分析操作栈发现,在 Canvas 上绘制时使用了 bolder
操作,但是由于该字体家族不存在粗体字重,因此实际的显示效果和 normal
相同。
因此,这是一个 bug。
在本案例中,比较 Canvas 操作得到的结论是正确的,比较 Canvas 内容得到的结论是漏报(false negative)的。
oblique
时,没有使用 italic
[1]var testCase = {
name: 'should display oblique different from italic',
option1: {
series: [],
title: {
text: 'oblique vs. italic',
textStyle: {
fontStyle: 'oblique'
}
}
},
option2: {
series: [],
title: {
text: 'oblique vs. italic',
textStyle: {
fontStyle: 'italic'
}
}
}
};
[1] italic
表示由设计师手动绘制的斜体字,而 oblique
是在显示时,在原字体样式上做斜切处理。事实上,很少有字体同时存在这两种样式,通常都是互相通用的。参见 font-style: italic vs oblique in CSS。
如果我们希望测试标题样式为 oblique
时,是否真正设置正确,我们是无从很难判断的。
我们只能判断该样式与 normal
、italic
等的结果不同,从侧面得出结论。
这一点在软件测试中是一个普遍存在的潜在问题。
测试结果表明:两种配置的 Canvas 内容是一致的,而操作是不一致的。
分析操作栈发现,绘制时的确分别使用了 oblique
与 italic
,但是由于两者显示效果一致,所以产生了以上分歧。
因此,这不是一个 bug。
在本案例中,比较 Canvas 操作得到的结论是正确的,比较 Canvas 内容得到的结论是误报(false positive)的。
通常比较 Canvas 操作得到的结论更稳健
比较操作也不总是符合预期的,取决于测试用例
(思考反例)