← Back to Upcase

Creating a tenant to use in tests


(Dan Weaver) #1

I’m starting to add tests to my existing app which uses default_scope for multi-tenancy. The tenant is School and almost every other object is scoped under current_school since the app has no public/anonymous access.

I started with a simple association :school in each factory (User, Lesson, Upload, etc) which was fine for model/unit tests but as soon I started doing integration tests I realized I need to be able to control which School my tests objects are created under.

I’ve added the following to my spec_helper.rb:

config.before(:suite) do
  School.create!(name: 'Main', subdomain: 'main')
  School.create!(name: 'Other', subdomain: 'other')
end

but how do I efficiently use these two ‘preset’ tenants in my factories and/or specs?


(Dan Weaver) #2

I’ve replaced association :school in every factory with this for now:

school School.where(name: 'Main').first

This is obviously very brittle but at least I can get back to writing tests for a while!


(Geoff Harcourt) #3

Ordinarily I’m not a fan of using “global” instance variables across all tests using @, but I think here since so many of your tests rely on it that having a @main_school and @other_school that you set up in a before(:all) do end block would probably be the best way to handle all of these tests. It is sort of a mystery guest, but if the association ends up getting used in 70-80% of your scenarios then it’s probably ubiquitous enough to bend the rules a little.


(Dan Weaver) #4

Thanks @geoffharcourt, that’s really good to know. Will I need to add such a before block to every _spec.rb file that references those variables? Or is there somewhere global I can put it?

Please excuse my ignorance - TTN (Total Testing Noob)


(Geoff Harcourt) #5

If you put it in a block like this in your spec helper it will work everywhere:

RSpec.configure do |config|
  config.before(:all) do
     # set up your models with @names
  end
end

If you include your support directory in spec helper, you can offload this into a separate file, otherwise you can just put the before statement in the big configuration block in spec helper.


(Dan Weaver) #6

@geoffharcourt That’s great, thanks. I’ve got that working.

I’d really like to be able to use these instance variables in my factories, is that possible? Like:

FactoryGirl.define do
  factory :teacher do
    school_id  School.where(name: 'Main').first.id # current_code 
    association :school, @main_school # is anything like this possible?
    name  { Faker::Name.first_name }
    email { Faker::Internet.safe_email }
  end
end

It would make my test code a lot slimmer if I could define @mail_school as the default association and just override it with @other_school when I’m testing isolation of data:

create(:teacher, school: @other_school)

I know I can leave the association out of the factory and pass in a school on every create but since the vast majority will use @main_school it seems like a lot of repetition.


(Geoff Harcourt) #7

I don’t think you can access instance variables from RSpec in your factory code, but if it’s possible you probably have to do the work in an after callback, which is explained in the FactoryGirl getting started doc.

Do you need to specify the ID and the association? The first two lines of your factory attributes seem like they are setting up the same association.


(Dan Weaver) #8

Thanks @geoffharcourt, I’ll check out the callback docs.

Sorry, I should’ve made my last post more clear - the line:

school_id School.where(name: 'Main').first.id

is what I’m currently using and I wanted to know if the line:

association :school, @main_school

is possible instead. I guess it isn’t.

Thanks for all your help on this. I feel like I’m actually making some progress with testing now!