Я использую Jasmine BDD Javascript-библиотеку и наслаждаюсь ею. У меня есть тестовый код, который я бы хотел повторно использовать (например, тестирование нескольких реализаций базового класса или запуск тех же тестов в немного другом контексте), и я не уверен, как это сделать с помощью Jasmine. Я знаю, что я мог бы переместить код из функций жасмина и в классы повторного использования, но мне нравится, как код читается вкрапленными функциями Jasmine (описать, он), и я не хочу отделять спецификации от тестового кода, если только я не должен. Кто-нибудь там, используя Жасмин, сталкивается с этой проблемой и как вы ее обрабатываете?
Какой хороший способ повторного использования тестового кода с помощью Jasmine?
Ответ 1
Мне было указано, чтобы обернуть вызов описания в функцию, которая передает ему параметр.
Ответ 2
Вот статья парня из Pivotal Labs, в котором подробно описывается, как обернуть вызов описания:
DRYing Jasmine Specs с общим поведением
Фрагмент из статьи, в которой показана часть функции обертки:
function sharedBehaviorForGameOf(context) {
describe("(shared)", function() {
var ball, game;
beforeEach(function() {
ball = context.ball;
game = context.game;
});
});
}
Ответ 3
Я не уверен, как работает решение @starmer. Как я упоминал в комментарии, когда я использую его код, context
всегда undefined.
Вместо того, что вам нужно сделать (как упоминалось в @moefinley), вместо этого следует передать ссылку на конструктор. Я написал сообщение в блоге, в котором описывается этот подход с использованием примера. Вот его суть:
describe('service interface', function(){
function createInstance(){
return /* code to create a new service or pass in an existing reference */
}
executeSharedTests(createInstance);
});
function executeSharedTests(createInstanceFn){
describe('when adding a new menu entry', function(){
var subjectUnderTest;
beforeEach(function(){
//create an instance by invoking the constructor function
subjectUnderTest = createInstanceFn();
});
it('should allow to add new menu entries', function(){
/* assertion code here, verifying subjectUnderTest works properly */
});
});
}
Ответ 4
Там хорошая статья на веб-сайте butbot: https://robots.thoughtbot.com/jasmine-and-shared-examples
Вот краткий пример:
appNamespace.jasmine.sharedExamples = {
"rectangle": function() {
it("has four sides", function() {
expect(this.subject.sides).toEqual(4);
});
},
};
И с некоторыми элементами подчеркивания для определения itShouldBehaveLike
window.itShouldBehaveLike = function() {
var exampleName = _.first(arguments),
exampleArguments = _.select(_.rest(arguments), function(arg) { return !_.isFunction(arg); }),
innerBlock = _.detect(arguments, function(arg) { return _.isFunction(arg); }),
exampleGroup = appNamespace.jasmine.sharedExamples[exampleName];
if(exampleGroup) {
return describe(exampleName, function() {
exampleGroup.apply(this, exampleArguments);
if(innerBlock) { innerBlock(); }
});
} else {
return it("cannot find shared behavior: '" + exampleName + "'", function() {
expect(false).toEqual(true);
});
}
};
Ответ 5
Это похоже на более резкий ответ, но после его работы я обнаружил некоторые отличия. Недостатком является то, что если спецификация не сработает, вы просто увидите, что "следует придерживаться общих спецификаций экономии" в отчете Jasmine. Трассировка стека - единственный способ найти, где это не удалось.
// common specs to execute
self.executeCommonSpecifications = function (vm) {
// I found having the describe( wrapper here doesn't work
self.shouldCallTheDisplayModelsSaveMethod(vm);
}
self.shouldCallTheDisplaysSaveMethod = function (vm) {
expect(vm.save.calls.count()).toBe(1);
};
// spec add an it so that the beforeEach is called before calling this
beforeEach(function(){
// this gets called if wrapped in the it
vm.saveChanges();
}
it('should adhere to common saving specifications', function () {
executeSavingDisplaysCommonSpecifications(vm);
});
Ответ 6
Это подход, который я сделал, вдохновленный этой статьей:
https://gist.github.com/traviskaufman/11131303
который основан на собственной документации Jasmine:
http://jasmine.github.io/2.0/introduction.html#section-The_%3Ccode%3Ethis%3C/code%3E_keyword
Установив общие зависимости как свойства прототипа функции beforeEach
, вы можете расширить beforeEach
, чтобы сделать эти зависимости доступными через this
.
Пример:
describe('A suite', function() {
// Shared setup for nested suites
beforeEach(function() {
// For the sake of simplicity this is just a string
// but it could be anything
this.sharedDependency = 'Some dependency';
});
describe('A nested suite', function() {
var dependency;
beforeEach(function() {
// This works!
dependency = this.sharedDependency;
});
it('Dependency should be defined', function() {
expect(dependency).toBeDefined();
});
});
describe('Check if string split method works', function() {
var splitToArray;
beforeEach(function() {
splitToArray = this.sharedDependency.split();
});
it('Some other test', function() { ... });
});
});
Я знаю, что мой пример бесполезен, но он должен служить своей целью в качестве примера кода.
Конечно, это всего лишь одна из многих вещей, которые вы могли бы сделать для достижения того, что вы говорите, я уверен, что более сложные шаблоны дизайна могут применяться сверху или в сторону этого.
Надеюсь, что это поможет!