Nano Hash - криптовалюты, майнинг, программирование

Тестирование создания связанных объектов при обратном вызове с помощью Rspec on Rails

Пытаюсь разобраться в rspec и правильном тестировании, и мне трудно сделать следующее правильно.

Допустим, у нас есть три класса, например

Class User
    belongs_to :company
    has_and_belongs_to_many :roles
end

Class Company
    has_many :users
end

Class Role
    has_and_belongs_to_many :users
end

В классе User у меня есть обратный вызов before_create, который назначает пользователю роль «company_admin» по умолчанию, если пользователь первым связан с компанией.

def check_for_initial_company_admin_role
  if self.company.users.count == 0
    self.roles << Role.find_by_name("company_admin")
  end
end

Как правильно проверить в спецификации моей модели, что пользователю назначается роль «company_admin», если он первый пользователь, связанный с компанией?


ОБНОВИТЬ рабочее решение

describe "#check_for_initial_company_admin_role" do
  it "sets the first user created to be the administrator" do
    Factory(:role)
    user = Factory(:user)

    user.roles.count.should be > 0
    user.roles.should include Role.find_by_name("company_admin")
  end
end


Factory.define :user do |f|
  f.email { Factory.next(:email) }
  f.password "secret"
  f.password_confirmation "secret"
  f.association :company
end 

Factory.define :role do |f|
  f.name "company_admin"
end

Factory.define :company do |f|
  f.name "foobar"
  f.vat_id "1234"
end
26.10.2011

Ответы:


1

Я бы подошел к этому так:

describe "#check_for_initial_company_admin_role" do
  it "sets the first user created to be the administrator" do
    company = Factory(:company)
    user = Factory(:user)
    company.users << user


    user.roles.count.should > 0
    user.roles.should include Role.find_by_name("company_admin")
  end
end

Предположение, которое здесь может быть неверным, заключается в том, что вы используете Factory Girl в своей тестовой среде. Если нет, это на самом деле не меняет «мясо» этого теста... только те первые строки, где вы создаете компанию и пользователя.

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

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

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

26.10.2011
  • OT: пожалуйста, используйте «be» при использовании «›»: user.roles.count.should be > 0 26.10.2011
  • Тем не менее, вам не нужно это ожидание, потому что оно подразумевается user.roles.should include(...). В противном случае я бы использовал тот же подход, за исключением того, что я, вероятно, сначала написал бы спецификацию;) 26.10.2011
  • ах, хороший момент. Я часто путаюсь в ожиданиях прямых логических отношений. Я добавлю это в мой внутренний список лучших практик. Спасибо! И да, в этом году я научился писать спецификацию, делать ее неудачной, реализовывать код, чтобы сделать ее зеленой :), действительно увлекся этим подходом. 26.10.2011
  • Я не думаю, что этот пример действительно будет работать. Он создает пользователя перед назначением его компании. Следовательно, компания будет нулевой, и обратный вызов сработает при вызове users в nilClass. 26.10.2011
  • Спасибо, ввел меня в курс дела. Я использую FG, и я не строил ассоциации пользователя и компании за один раз, и поэтому обратный вызов класса User на before_save завершится ошибкой, потому что не было объекта компании. Я обновил вопрос, чтобы показать рабочее решение 26.10.2011

  • 2

    Не меняя вашей существующей логики, я бы проверил эту логику в user_spec следующим образом:

    describe User do
      let!(:admin_role) { Role.create!(name: 'company_admin') }
      let!(:company) { Company.create! }
    
      it 'should be added to the default role when created' do
        user = company.users.create!(name: 'Joe', email: '[email protected]')
    
        user.should have(1).roles
        user.roles.first.should == admin_role
      end
    end
    

    Примечание. Я бы использовал что-то вроде FactoryGirl для роли администратора и объектов компании, чтобы сделать их многоразовыми.

    Использование вами имени роли для обозначения поведения не является идеальным. Скорее всего, это приведет к большому количеству разрозненной логики в вашем приложении, где вы находите роль по ее имени и проверяете имя с помощью операторов if/else или case. Я бы рекомендовал использовать наследование одной таблицы Rail и перенести всю логику роли администратора в отдельный класс. Это сохранит логику модели более чистой и значительно упростит тестирование.

    26.10.2011
  • Спасибо. Причина использования роли в качестве отдельного объекта исходит из использования Devise/CanCan для управления задачами аутентификации/авторизации. 26.10.2011
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..