Создание поддельного object.method() с нуля в sinon?

tl;dr

Как вы создаете object.method() «с нуля» в sinon?

контекст

Например, у меня есть семейство классов Parser, каждый из которых реализует метод #parse(text) и возвращает объект ParseTree или возвращает null.

Я выполняю модульное тестирование, где я не тестирую сами объекты Parser (они тестируются в другом месте), но мне нужен тестируемый объект, который отвечает на #parse(). Я мог бы создать и заглушить настоящий синтаксический анализатор, но это затянет ненужный код в эту часть теста.

вопрос

Я почти уверен, что это легко сделать с помощью API-интерфейсов sinon spy(), stub() и/или mock(), поэтому: как мне создать тестируемый объект, который:

  • отвечает на метод parse()
  • проверяет, что он вызывается один раз
  • возвращает произвольный объект, который я указываю?

что я пробовал

В следующем надуманном примере происходит сбой при вызове sinon.stub(), поскольку объект sinon.spy() не может быть заглушен методом parse. (Этот пример также должен подтвердить, что fake_parser.parse() был вызван один раз с test_text, но это не так):

var test_text = 'any text'
var fake_parse_tree = sinon.spy()
var fake_parser = sinon.stub(sinon.spy(), 'parse').returns(fake_parse_tree)

expect(fake_parser.parse(test_text)).to.equal(fake_parse_tree)

person fearless_fool    schedule 12.05.2015    source источник


Ответы (2)


Создайте фиктивный объект Parser и заглушите его метод parse(). Детали будут зависеть от того, как вы создаете свои парсеры, но что-то вроде:

var Parser = {
    parse: function() { }
};

var parseStub = sinon.stub(Parser, 'parse');
parseStub.returns(fake_parse_tree);

// execute code that invokes the parser

parseStub.callCount.should.equal(1);
parseStub.alwaysCalledWithExactly(test_text).should.be.true();
person Stephen Thomas    schedule 12.05.2015
comment
Ах! Ключевым моментом является то, что sinon.stub(obj, method) возвращает заглушенный МЕТОД, а не объект. Я запутался, потому что пытался передать parseStub в свой код, который ожидал парсер. Спасибо! - person fearless_fool; 12.05.2015

@Stephen Thomas дал здесь правильный ответ. Для дальнейшего использования, вот что я наконец сделал. «Ага» заключается в том, что sinon.stub(object, 'method') возвращает заглушенный метод, а не объект.

Поскольку это javascript (а методы являются объектами первого класса), возврат метода имеет смысл:

var test_text = 'any text';
var parse_tree = sinon.spy(); // could be any object
var proxy_parser = { parseText: function() { } };
var stubbed_method = sinon.stub(proxy_parser, 'parseText').returns(parse_tree)

// App specific tests not shown here:
// ...pass proxy_parser to a function that calls proxy_parser.parseText()
// ...verify that the function returned the parse_tree

expect(stubbed_method.callCount).to.equal(1)
expect(stubbed_method.alwaysCalledWithExactly(test_text)).to.be.true
person fearless_fool    schedule 12.05.2015