Я знаком с RSpec, где очень легко повторно использовать контрольные примеры, написав общие примеры

shared_example_for 'a cute pet' do 
  it 'tests that the pet is a small' { expect(pet.size).to be_lesser_than(10) }
  it 'tests that the pet can smile' { expect(pet.can_smile?).to be }
end

describe 'The Octocat' do
  let(:pet) Octocat.new

  it_behaves_like 'a cute pet'
end
...
describe 'The Doge' do 
  let(:pet) Doge.new

  it_behaves_like 'a cute pet'
end

Есть ли эквивалент в Jest? Что-то, что позволило бы мне повторно использовать переменные, установленные в блоках beforeEach ()? Я пытаюсь найти способ, используя что-то вроде следующего:

# __tests__/cuteness.js
export const cutenessTests = function() {
  test('it is small', () => {
    expect(petSetInBefore.length).toBeLesserThan(5)
  })
  test('it can smile', () => {
    expect(petSetInBefore.canSmile).toBe(true)
  })
}

# __tests__/famous_animals.test.js
import { cutenessTests } from './cuteness'

describe('Famous animals', () => {
  let petSetInBefore;

  describe('Octocat', () => {
    beforeEach(() => {
      petSetInBefore = new Octocat();
    })

    cutenessTests.bind(this)()
  })
})

Здесь важно то, что я пытаюсь разделить несколько определений test, а не только одно, иначе я мог бы передать petSetInBefore в общую функцию.

РЕДАКТИРОВАТЬ: каждый из моих тестов и вложенных описаний может изменить мою тестовую среду и объекты, поэтому beforeEach используется для восстановления правильной тестовой среды. Вот лучший пример

class Octocat {
  get strokeFor(time) {
    this.strokeTime = this.strokeTime + time
    if (this.strokeTime <= 10) {
      this.mood = 'happy'
    } else {
      this.mood = 'bored'
    }
  }
}

class Doge {
  get strokeFor(time) {
    this.strokeTime = this.strokeTime + time
    if (this.strokeTime <= 5) {
      this.mood = 'happy'
    } else {
      this.mood = 'bored'
    }
  }
}

const cutenessTests = function() {
  describe('when stroked for a short while', () => {
    beforeEach(() => {
      petSetInBefore.strokeFor(1);
    })

    test('it is happy', () => { expect(petSetInBefore.mood).to(eq('happy')) }

    describe('when stroked too much', () => {
      beforeEach(() => {
        petSetInBefore.stroke(1000);
      })

      test('it gets bored', () => { expect(petSetInBefore.mood).to(eq('bored')) }
    })

    describe('when stroked a little longer', () => {
      beforeEach(() => {
        petSetInBefore.strokeFor(4);
      })

      test('it is still happy', () => { expect(petSetInBefore.mood).to(eq('happy')) }
    })
  })
}

РЕДАКТИРОВАТЬ 2: Вот repl.it на основе Ответ Gui3

РЕДАКТИРОВАТЬ3: объект может быть изменен до или во время повторных испытаний

describe('Famous animals', () => {
  let petSetInBefore;

  describe('Octocat', () => {
    beforeEach(() => {
      petSetInBefore = new Octocat();
    })

    describe('when it is not well rested', () => { 
      beforeEach(() => { petSetInBefore.wellRested() } // Extra object preparation / context before calling reusable examples
      cutenessTests()
    }),
    describe('when it is not well rested', () => { 
      // Calling reusable examples without extra context
      cutenessTests()
    })
  })
})
13
Cyril Duchon-Doris 20 Авг 2018 в 16:48

3 ответа

Лучший ответ

Если вы все еще хотите beforeEach ,

По причинам ... это работает, если вы объявите свою переменную в глобальной области видимости

let petSetInBefore; // here it works
describe('Famous animals', () => {
  //let petSetInBefore; // here it's undefined

  describe('Octocat', ()  => {
    //let petSetInBefore; // undefined too

    beforeAll(() => {
      petSetInBefore = new Octocat();
    })

    cutenessTests() // .bind(this) results the same
  });

  describe('Doge', () => {
    beforeEach(() => {
      petSetInBefore = new Doge();
    })

    cutenessTests.bind(this)()
  });
})

https://repl.it/@gui3/jestSharedTests

Похоже, что тесты внутри разделяемой функции не могут совместно использовать переменные из beforeEach в противном случае ...

3
gui3 24 Ноя 2019 в 16:48

В Jest есть describe.each(table), который я не видел используется много раз, но это действительно полезно для повторного использования тестов, которые имеют общие / одинаковые результаты.

В случае одинаковых ожиданий для обоих испытуемых, вы можете сделать это следующим образом:

const aCutePet = pet => {
  it("should be small", () => {
    expect(pet.size).toBeLessThan(10);
  });

  it(`should be able to smile`, () => {
    expect(pet).toHaveProperty('can_smile', true)
  });
}

describe.each([
  [new Doge],
  [new Octocat]
])("The %O", aCutePet);

Выход:

  The Doge { size: 3, can_smile: true }
    ✓ should be small (1ms)
    ✓ should be able to smile (1ms)
  The Octocat { size: 5, can_smile: true }
    ✓ should be small
    ✓ should be able to smile (1ms)
0
Teneff 24 Ноя 2019 в 20:42

Вы можете просто переместить общие тесты в функцию, которая выполняет вызовы it().

class Octocat {
  get length() {
    return 3;
  }

  get canSmile() {
    return true;
  }
}

class GrumpyCat {
  get length() {
    return 1;
  }

  get canSmile() {
    return false;
  }
}

const behavesLikeAPet = (pet) => {
  it('is small', () => expect(pet.length).toBeLessThan(5));
  it('can smile', () => expect(pet.canSmile).toEqual(true));
};

describe('Famous animals', () => {
  describe('Octocat', () => {
    behavesLikeAPet(new Octocat());
  });

  describe('GrumpyCat', () => {
    behavesLikeAPet(new GrumpyCat());
  });
});

Вы получите подробный вывод для каждого теста:

Famous animals
  Octocat
    ✓ is small (2ms)
    ✓ can smile (1ms)
  GrumpyCat
    ✓ is small
    ✕ can smile (2ms)
3
timotgl 24 Ноя 2019 в 16:09
51932183