Подтвердить что ты не робот

Тестирование на холсте HTML

Как я могу тестировать Javascript, который использует HTML-холст? Рисование на холсте должно быть проверено.

4b9b3361

Ответ 1

Как обсуждалось в комментариях к вопросу, важно проверить, что определенные функции были вызваны с помощью подходящих параметров. pcjuzer предложил использовать прокси-шаблон. Следующий пример (код RightJS) показывает один из способов сделать это:

var Context = new Class({
    initialize: function($canvasElem) {
        this._ctx = $canvasElem._.getContext('2d');

        this._calls = []; // names/args of recorded calls

        this._initMethods();
    },
    _initMethods: function() {
        // define methods to test here
        // no way to introspect so we have to do some extra work :(
        var methods = {
            fill: function() {
                this._ctx.fill();
            },
            lineTo: function(x, y) {
                this._ctx.lineTo(x, y);
            },
            moveTo: function(x, y) {
                this._ctx.moveTo(x, y);
            },
            stroke: function() {
                this._ctx.stroke();
            }
            // and so on
        };

        // attach methods to the class itself
        var scope = this;
        var addMethod = function(name, method) {
            scope[methodName] = function() {
                scope.record(name, arguments);

                method.apply(scope, arguments);
            };
        }

        for(var methodName in methods) {
            var method = methods[methodName];

            addMethod(methodName, method);
        }
    },
    assign: function(k, v) {
        this._ctx[k] = v;
    },
    record: function(methodName, args) {
        this._calls.push({name: methodName, args: args});
    },
    getCalls: function() {
        return this._calls;
    }
    // TODO: expand API as needed
});

// Usage
var ctx = new Context($('myCanvas'));

ctx.moveTo(34, 54);
ctx.lineTo(63, 12);

ctx.assign('strokeStyle', "#FF00FF");
ctx.stroke();

var calls = ctx.getCalls();

console.log(calls);

Вы можете найти функциональную демонстрацию здесь.

Я использовал подобный шаблон для реализации некоторых функций, отсутствующих в API. Возможно, вам придется немного взломать его, чтобы он соответствовал вашим целям. Удачи!

Ответ 2

Я написал пример для модульного тестирования canvas и других типов image-y с Jasmine и js-imagediff.

Тестирование блоков холста Jasmine

Я считаю, что это лучше, чем использование определенных методов на макете Canvas, потому что разные серии методов могут создавать один и тот же метод. Как правило, я создаю холст с ожидаемым значением или пользуюсь известной стабильной версией кода для тестирования версии разработки.

Ответ 3

Я делаю действительно простые холсты и тестирую их с моккой. Я делаю это так же, как и Юхо Вепсаляйнен, но мой выглядит немного проще. Я написал его в ec2015.

Класс CanvasMock:

import ContextMock from './ContextMock.js'

export default class {
  constructor (width, height)
  {
    this.mock = [];
    this.width = width;
    this.height = height;
    this.context = new ContextMock(this.mock);
  }

  getContext (string)
  {
    this.mock.push('[getContext ' + string + ']')
    return this.context
  }
}

Класс ContextMock:

export default class {
  constructor(mock)
  {
    this.mock = mock
  }

  beginPath()
  {
    this.mock.push('[beginPath]')
  }

  moveTo(x, y)
  {
    this.mock.push('[moveTo ' + x + ', ' + y + ']')
  }

  lineTo(x, y)
  {
    this.mock.push('[lineTo ' + x + ', ' + y + ']')
  }

  stroke()
  {
    this.mock.push('[stroke]')
  }
}

некоторые мокко-тесты, которые оценивают функциональность самого макета:

describe('CanvasMock and ContextMock', ()=> {
    it('should be able to return width and height', ()=> {
      let canvas = new CanvasMock(500,600)
      assert.equal(canvas.width, 500)
      assert.equal(canvas.height, 600)
    })
    it('should be able to update mock for getContext', ()=> {
      let canvas = new CanvasMock(500,600)
      let ctx = canvas.getContext('2d')
      assert.equal(canvas.mock, '[getContext 2d]')
    })
})

Тест mocha, который оценивает функциональность функции, которая возвращает холст:

import Myfunction from 'MyFunction.js'

describe('MyFuntion', ()=> {
it('should be able to return correct canvas', ()=> {
  let testCanvas = new CanvasMock(500,600)
  let ctx = testCanvas.getContext('2d')
  ctx.beginPath()
  ctx.moveTo(0,0)
  ctx.lineTo(8,8)
  ctx.stroke()
  assert.deepEqual(MyFunction(new CanvasMock(500,600), 8, 8), canvas.mock, [ '[getContext 2d]', '[beginPath]', '[moveTo 0, 0]', [lineTo 8, 8]', '[stroke]' ])
})

поэтому в этом примере myfunction принимает холст, который вы передали в качестве аргумента (Myfunction ( new CanvasMock (500 600), 8, 8)) и записывает строку на нем от 0,0 до любой вы передаете аргументы (Myfunction (новый CanvasMock (500,600), ** 8, 8 **)), а затем возвращает отредактированный холст.

поэтому, когда вы используете эту функцию в реальной жизни, вы можете передать фактический холст, а не холст-макет, а затем он будет запускать те же самые методы, но делать фактические холсты.

читать о mocks здесь

Ответ 4

Недавно я смотрел на холст-тестирование, и теперь я подумал о странице, которая позволяет сравнивать холст с "хорошо известной" версией образа того, что должно выглядеть холст. Это сделало бы визуальное сравнение быстрым и легким.

И, может быть, есть кнопка, которая, если вывод будет в порядке, обновляет версию изображения на сервере (отправив на него вывод toDataUrl()). Затем эту новую версию можно использовать для будущих сравнений.

Не совсем (вообще) автоматизировано - но он действительно упрощает сравнение вывода вашего кода.

Edit:

Теперь я сделал это:

Utility to test canvas output

Левая диаграмма - это реальный холст, а справа - изображение, хранящееся в базе данных, как оно должно выглядеть (взято с того момента, когда я знаю, что код работает). Их будет много, чтобы проверить все (в конечном счете) аспекты моего кода.

Ответ 5

С точки зрения разработчика холст почти записывается только потому, что некогда было сложно программно получить что-то полезное. Конечно, можно сделать точечное распознавание, но это слишком утомительно, и такие тесты трудно писать и поддерживать.

Лучше перехватить вызовы, сделанные для объекта canvas, и исследовать их. Вот несколько вариантов:

  • Создайте объект-обертку, который записывает все вызовы. Юхо Вепшаляйнен опубликовал такой пример.
  • Если возможно, используйте библиотеку, например frabric.js, которая предлагает более высокий уровень абстракции для рисования. "Рисунки" представляют собой объекты JS, которые могут быть проверены напрямую или преобразованы в SVG, которые легче проверить и проверить.
  • Используйте Canteen, чтобы перехватить все вызовы функций и изменения атрибутов объекта canvas. Это похоже на вариант 1.
  • Используйте столовую с rabbit, который предлагает вам несколько настраиваемых совпадений Jasmine для размера и выравнивания и функцию getBBox(), которая может быть используемый для определения размера и положения материала, нарисованного на холсте.

Ответ 6

Так как "фигуры" и "линии", нарисованные на холсте, не являются реальными объектами (это как чернила на бумаге), было бы очень сложно (невозможно?) сделать нормальный unit test на этом.

Лучшее, что вы можете сделать со стандартным холстом, оно анализирует данные пикселей (из putImageData/getImageData. Как то, что говорило bedraw).

Теперь я еще не пробовал это, но это может быть больше того, что вам нужно. Торт - это библиотека для холста. Он использует много данных putImageData/getImageData. Этот пример может помочь с тем, что вы пытаетесь сделать с тестом.

Надеюсь, что поможет ответить на ваш вопрос.