D3JS的单元测试策略是什么?

时间:2014-02-10 08:59:24

标签: d3.js

我是D3JS的新手,想了解D3 JS的测试策略。

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

Java脚本代码:

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

我无法考虑编写单元测试时要考虑的测试用例。这是我写的一个示例测试..

it("should throw an exception if line graph properties are not set.", function() {
        expect(lineManager.draw.bind(lineManager)).toThrow("Line Graph properties not set");
    });

it("It should have single line chart", function() {
    lineManager.draw(properties);
    expect(lineManager.countLines()).toEqual(1);
});

我编写了单元测试以确保正确生成TSV文件。但编写单元测试以查看数据是否正确呈现是否有意义?这不是更多的d3js单元测试而不是单元测试我的功能吗?

所以我的问题是 - 对d3js生成的图表应该考虑哪些测试?

4 个答案:

答案 0 :(得分:9)

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

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

我担心的是传递给D3JS的数据是否正确并且符合我的要求。通过创建Spy对象,可以确保正确设置图形的属性。我正在提供一个样本单元测试,涵盖使用D3JS绘制圆形的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');
    });
});

希望这有帮助。

答案 1 :(得分:5)

测试策略

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

关于绘图函数,它可能会变得棘手,但是使用诸如buster.js之类的测试框架也可以非常容易地实现它们。测试图表的一种好方法是计算页面中条形图/线条的数量,检查图例是否正在打印等。

我不会尝试检查图表在视觉上是否相同,因为直观地检查最终结果是否相同是最简单的。但是,在编写绘图函数时,应该非常注意更新时发生的事情(将数据绘制的数量改为两倍?选择器是否正确?...)


Javascript测试

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


工具

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

buster.js

Buster.js是一个非常完整的框架,用于在多个浏览器中对javascript代码进行单元测试。

phantom.js

  

Phantom.js是一个带有JavaScript API的无头WebKit脚本。

这意味着它可以轻松地在javascript上运行自动化测试,而无需使用chrome,safari等浏览器。


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

答案 2 :(得分:5)

我认为你应该考虑这个:http://busypeoples.github.io/post/testing-d3-with-jasmine/

它似乎真的有道理。我读过其他人&#39;答案,但我有点不同意他们。我认为我们不仅要检查是否调用了正确的函数,而且我们可以检查更多。仅检查一些函数调用是否适合单元测试级别但不够。开发人员编写的这些测试用例将基于开发人员的理解,就像调用或不调用这些函数一样。但是,无论是否应该调用这些方法,只能通过另一个级别来检查这个东西,因为与其他工作不同,这里的代码是使某些东西不能返回可以被检查的东西,并确保一切正确。

我们显然不需要检查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函数级别只需要进行单元测试,那么可以测试更多的东西而不需要进入元素细节。

答案 3 :(得分:0)

可能值得一提的是 Jest 快照测试。 Jest / snapshots很受 React UI组件的欢迎,因为它们也很难测试。使用 D3 ,您可以生成一个SVG拍摄快照并验证您的代码库是否会继续生成相同的输出。

function makeChart(id, dataset) {
  const chart = d3.select(id)
      .append("svg")
      .selectAll("circle")
      .data(dataset)
      .enter().append("circle")
      .style("stroke", "gray")
      .style("fill", "black")
      .attr("r", 40)
      .attr("cx", 50)
      .attr("cy", 20);
  return chart;
}

it('renders correctly', () => {
  const myChart = makeChart('#example', [1,2,3])
  expect(myChart.node()).toMatchSnapshot();
});

此测试未经测试

快照可以是字符串"Foo Bar"和JSON对象{foo: "bar"}等的任何输出。

基本上,您必须运行包含.toMatchSnapshot的测试。然后,Jest将管理生成并存储它将在以后的测试中进行比较的副本。

这个概念类似于Ruby测试中的 VCR 。录制和重播。