rspec способ передачи переменной между несколькими контекстами

Мне было интересно, как лучше всего передавать переменную между несколькими контекстами (или несколькими контекстами) в rspec, но без использования глобальных переменных?

Например, у меня это:

describe "My test" do
    let(:myvar) { @myvar = 0 }

    context "First test pass" do
        it "passes" do
            myvar = 20
            expect(myvar).to eq(20)
        end
    end

    context "Second test pass" do
        it "passes" do
            expect(myvar).to eq(20)
        end
    end
end

Теперь, очевидно, это не будет работать с let, потому что с новым контекстом переменная myvar вернется в исходное состояние, равное = 0. Мне понадобится механизм для «кэширования состояния» между двумя контекстами, который, в свою очередь, даст мне значение myvar = 20 во втором контексте

Любые мнения, предложения и улучшения приветствуются. Спасибо


person Bakir Jusufbegovic    schedule 12.12.2014    source источник
comment
Лучше просто не передавать переменную между контекстами. Если вам нужен контекст, создайте его в блоке контекста.   -  person shirakia    schedule 12.12.2014


Ответы (3)


Другой простой способ - определить «локальную переменную» в контексте описания. «локальная переменная» будет существовать на протяжении всего описания, и любые изменения во время выполнения повлияют на нее и, таким образом, изменят ее.

Например

describe 'tests' do
    context 'Sharing a variable across tests' do
        var = 1
        puts var

        it "it one. var = #{var}" do
            var = var*2
            puts var
        end
        it "it two" do
            puts var
        end
    end
end 

Вывод

1
2
1
person Rony G    schedule 31.05.2016

  1. Происходит не то, что вы думаете.
  2. То, что вы хотите сделать, ломает «модульное тестирование» как методологию.

Позвольте мне сначала объяснить № 2 - тестовые примеры модульного тестирования должны уметь работать изолированно, что означает, что они должны работать, когда запускаются вместе, когда запускаются по отдельности и в любом порядке ... настолько, что что некоторые фреймворки модульного тестирования (например, тот, который используется по умолчанию в elixir) запускать тестовые примеры в параллельном ...

Что касается №1 - когда вы пишете myvar = 20, вы не присваиваете значение let(:myvar) { @myvar = 0 }, вы просто создаете локальную переменную, которая переопределит все вызовы myvar внутри метода, но не будет доступна вне метода (myvar вернет 0).

Даже если бы вы вместо этого установили @myvar = 20 (если вы не сделаете это перед вызовом myvar в первый раз), myvar все равно вернет 0, поскольку функция let использует памятный знак шаблон, что означает, что он вызывается один раз, а последующие вызовы возвращают первоначально возвращенное значение (в данном случае 0):

puts myvar
@myvar = 20
puts myvar

# => 0
# => 0
person Uri Agassi    schedule 12.12.2014
comment
Итак, в двух словах, давайте дадим нам возможность определить начальное состояние (будь то объект или простой тип), которое можно использовать в последующих контекстах, но не изменять? - person Bakir Jusufbegovic; 12.12.2014
comment
@BakirJusufbegovic - нет, он воссоздается для каждого тестового примера, но не внутри тестового примера (более одного раза) - person Uri Agassi; 12.12.2014
comment
Это означает, что let воссоздается между примерами (это), но не в одном и том же примере (при многократном использовании). Угадай, пусть не может использоваться для механизма, который мне нужен, и это способность кэшировать состояние некоторой переменной между примерами. Я понимаю, что модульное тестирование не должно работать таким образом (тесты должны быть независимыми), но я использую RSpec для функциональных тестов, где эти примеры (или я бы предпочел называть их этапами тестирования) выполняются в последовательном порядке, и часто вывод некоторых примеров будет потребуются в качестве входных данных для следующего - person Bakir Jusufbegovic; 13.12.2014

Я столкнулся с той же проблемой. Я решил это с помощью драгоценного камня factory_girl.

Вот основы:

создать фабрику:

require 'factory_girl'
require 'faker' # you can use faker, if you want to use the factory to generate fake data

FactoryGirl.define do
  factory :generate_data, class: MyModule::MyClass do
    key 100 # doesn't matter what you put here, it's just a placeholder for now
    another_key 'value pair'
  end
end

Теперь, когда вы создали фабрику, вам нужно создать модель, которая выглядит следующим образом:

Module MyModule
  class MyClass
    #for every key you create in your factory you must have a corresponding attribute accessor in the model.
    attr_accessor :key, :another_key

    #you can also place methods here to call from your spec test, if you wish
    # def self.test
        #some test
    # end
  end
end

Теперь, возвращаясь к вашему примеру, вы можете сделать что-то вроде этого:

describe "My test" do
    let(:myvar) { @myvar }

    context "First test pass" do
        it "passes" do
            @myvar.key = 20 #when you do this you set it now from 100 to 20
            expect(@myvar.key).to eq(20)
        end
    end

    context "Second test pass" do
        it "passes" do
            expect(@myvar.key).to eq(20) #it should still be 20 unless you overwrite that variable
        end
    end
end

Как утверждают другие, неправильный способ модульного тестирования. Но как нам узнать, тестируете вы модульное устройство или нет? Так что судить не буду. В любом случае, удачи, дайте нам знать, если у вас есть другое решение!

person adbarads    schedule 03.09.2015