2014-02-10 40 views
16

我对D3JS是全新的,并且想了解D3 JS的测试策略。什么是D3JS的单元测试策略?

为了详细说明问题 - 考虑我有一个简单的页面,显示使用TSV文件的线图。

Java脚本代码:

function LineManager() {} 
function LineProperties() { // Line Properties } 
LineManager.prototype.draw = function(properties) { 
    // D3 code to draw a line with the given properties. 
} 

我不能想到的测试用例考虑编写单元测试。这里是我写的一个样本测试..我写了单元测试,以确保正确生成TSV文件。但编写一个单元测试以查看数据是否正确渲染是否有意义?对于我的功能来说,更多的是单元测试而不是单元测试吗?

所以我的问题是 - 什么测试应该考虑由d3js生成的图表?

+0

我总是会测试任何与数据相关的部分,然后用d3来绘制数据。因此,例如,如果你正在创建一个累积线图,我会检查[0,5,2,1]是否转换为[0,5,7,8],然后应用于选择和黎明(以及那些不常见的情况优雅地处理)。有兴趣看看还有其他什么。 –

+0

这样做的一种方法是使用[Selenium](http://docs.seleniumhq.org/)。 –

+0

您可能需要查看我的答案,我已编辑它。我不同意你的回答,并解释了理由。希望它会有所帮助。 – Hafiz

回答

6

我想我得到了我自己的问题的答案。将尝试在这里解释它。

无法通过使用D3JS编写的JS函数来验证图形是否被正确绘制。为此,我们可能不得不使用Chrisopher提到的Phantom.js或类似的框架。我并不担心确保D3JS正确地绘制图形,因为任何方式都是D3JS功能,我的代码可以安全地假定D3JS正在完成其工作。

我的担心更多的是传递给D3JS的数据是否正确并符合我的要求。通过创建间谍对象来确保图形的属性是非常可能的。我正在提供一个样本单元测试,其中包含使用D3JS绘制Circle的JS代码的测试用例。

CircleManager.js

function CircleManager() {}; 

CircleManager.prototype.draw = function(radius) { 
    var svg = d3.select("body") 
      .append("svg"); 

    svg.attr("width", 100) 
      .attr("height", 100);  

    var circle = svg.append("circle"); 
    circle.style("stroke", "black") 
     .style("fill", "white") 
     .attr("r", radius) 
     .attr("cx", 50) 
     .attr("cy", 50); 
}; 

CircleManagerSpec.js

describe("draw", function() { 
    it("Constructs an svg", function() { 
     var d3SpyObject = jasmine.createSpyObj(d3, ['append', 'attr']); 

     // Returns d3SpyObject when d3.select method is called 
     spyOn(d3, 'select').andReturn(d3SpyObject); 

     var svgSpyObject = jasmine.createSpyObj('svg', ['append', 'attr', 'style']); 

     // Returns svgSpyObject when d3.select.append is called. 
     d3SpyObject.append.andReturn(svgSpyObject); 


     d3SpyObject.attr.andCallFake(function(key, value) { 
      return this; 
     }); 

     svgSpyObject.append.andReturn(svgSpyObject); 

     svgSpyObject.attr.andCallFake(function(key, value) { 
      return this; 
     }); 

     svgSpyObject.style.andCallFake(function(key, value) { 
      return this; 
     }); 

     var circleManager = new CircleManager(); 
     circleManager.draw(50); 
     expect(d3.select).toHaveBeenCalledWith('body'); 
     expect(d3SpyObject.append).toHaveBeenCalledWith('svg'); 
     expect(svgSpyObject.attr).toHaveBeenCalledWith('r', 50); 
     expect(svgSpyObject.attr).toHaveBeenCalledWith('width', 100); 
     expect(svgSpyObject.attr).toHaveBeenCalledWith('height', 100); 
     expect(svgSpyObject.style).toHaveBeenCalledWith('stroke', 'black'); 
     expect(svgSpyObject.style).toHaveBeenCalledWith('fill', 'white'); 
    }); 
}); 

希望这有助于。

3

测试策略

我最终使用测试d3.js代码的策略是创建辅助功能来管理我的数据和设置。然后我单元测试这些功能。所以对于图表,我会检查处理数据的每个功能,每个函数设置宽度,图例等...

关于绘图函数可能会变得更复杂,但使用诸如buster.js之类的测试框架,它可以很容易实现这些也是。测试图表的一个好方法是计算页面中的条纹/线条数量,检查图例是否正在打印等。

我不会尝试检查图表在视觉上是否相同,因为从视觉上检查最终结果是一样的最简单。然而,书写绘图函数时,一个应该是非常关注的更新会发生什么情况(将改变数据中得出的两倍多行?是选择正确的?...)


的Javascript测试

一本关于javascript测试的好书是:Test Driven Javascript Development。它提供了大量的示例和策略来测试JavaScript代码。他们中的大多数可以直接应用于d3.js代码。


工具

我最近找了单元测试d3.js代码解决方案,我结束了使用以下工具:

buster.js

Buster.js是一个非常完整的框架,用于在多个浏览器中测试JavaScript代码。

phantom.js

Phantom.js是一个无头WebKit的编写脚本通过一段JavaScript API。

这意味着它可以很容易地运行JavaScript的自动化测试,而不需要使用浏览器,如Chrome浏览器,Safari浏览器等。


编辑:我现在会用茉莉花为单位测试和硒(可能通过Saucelabs服务)进行端到端测试。

3

我想你应该考虑一下:http://busypeoples.github.io/post/testing-d3-with-jasmine/

它真的似乎是有道理的。我已阅读其他人的答案,但我有点不同意他们。我想我们不仅要检查是否调用了正确的函数,而且我们可以检查更多的东西。仅检查一些函数调用擅长于单元测试级别,但还不够。开发人员编写的这些测试用例将基于开发人员的理解,就像这些函数被调用或不调用一样。但是,不管这些方法是否应该被调用,这个事情只能通过在另一个层次上进行检查,因为与其他工作不同,这里是代码正在做的事情没有返回可以检查的东西,并确保一切都是正确的。

我们显然不需要检查D3是否正常工作。所以我们可以在我们的测试代码中使用D3。但D3呈现SVG,我们可以检查像svg是否具有预期的元素。再次,它不会测试SVG是否正常显示和渲染。我们将检查SVG是否有预期的元素,并按预期设置。

例如: 如果这是条形图,我们可以检查条的数量。正如上面的链接中的示例,这是检查。

// extend beforeEach to load the correct data... 
beforeEach(function() { 
    var testData = [{ date: '2014-01', value: 100}, { date: '2014-02', value: 140}, {date: '2014-03', value: 215}]; 
    c = barChart(); 
    c.setData(testData); 
    c.render(); 
}); 

describe('create bars' ,function() { 
    it('should render the correct number of bars', function() { 
     expect(getBars().length).toBe(3); 
    }); 

    it('should render the bars with correct height', function() { 
     expect(d3.select(getBars()[0]).attr('height')).toBeCloseTo(420); 
    }); 

    it('should render the bars with correct x', function() { 
     expect(d3.select(getBars()[0]).attr('x')).toBeCloseTo(9); 
    }); 

    it('should render the bars with correct y', function() { 
     expect(d3.select(getBars()[0]).attr('y')).toBeCloseTo(0); 
    }); 
}); 

// added a simple helper method for finding the bars.. 
function getBars() { 
    return d3.selectAll('rect.bar')[0]; 
} 

有人可能会说我们要在测试代码中使用D3吗?我们应该再次记住,这里测试的目的不是测试D3,而是我们的逻辑和SVG代码,它们是为了响应我们的代码而编译的。

这只是一种方式,茉莉花是帮助我们写作测试的东西,您也可以进入更多细节和不同场景。您可以制作域并检查数据点宽度高度,以交叉检查数据点是否会导致渲染数据。

我觉得我很清楚,如果没有则检查此链接:你如何使用茉莉http://busypeoples.github.io/post/testing-d3-with-jasmine/

下面这篇文章的写有详细解释了事情。 另外,我认为我仍然深入细节。如果只需要在不同的js功能级别进行单元测试,那么还有更多的东西可以在不进入元素细节的情况下进行测试。

+0

请注意,[只有链接的答案](http://meta.stackoverflow.com/tags/link-only-answers/info)不鼓励,所以答案应该是寻求解决方案的最终目标。而另一个引用的中途停留时间往往会随着时间推移而过时)。请考虑在这里添加一个独立的简介,保持链接作为参考 – kleopatra

+0

@kleopatra你是对的,但在这里他想要战略知道他应该如何继续,我认为这个链接显示了他可以测试什么,以及他可以测试多少。 – Hafiz

+1

在一天结束时,如果您想按照本网站的规则进行游戏,那么这是您的决定;-)请注意,您的帖子 - 因为它是现在 - 不是一个有效的答案,并且可能会被删除(不是我会主张它,但可能会发生)。祝你好运! – kleopatra