0

I am writing RSpec tests to make sure my database associations work properly. I noticed that immediately after resetting the database, my tests always fail. They always expect an object but get nil instead. I also noticed that immediately after writing a new test, the new test will fail. If I run the test suite once again and the tests were correct to begin with, they all pass.

How do I make my tests pass immediately after a test database reset?

Here's a sample test file:

    describe 'Player' do

        let(:clan) {Clan.first || Clan.create(name: "Test Clan")}
        let(:kingdom) {Kingdom.first || Kingdom.create}
        let(:player) {Player.first || Player.create(username: "Foo", uuid: "9b15dea6-606e-47a4-a241-420251703c59", clan_id: 1, clan_role: "member", kingdom_id: 1, kingdom_role: "pleb")}
        let(:ip_address) {IpAddress.first || IpAddress.create(ip: "55.55.555.55")}
        let(:punishment) {Punishment.first || Punishment.create(offender_id: 1)}
        let(:connection) {Connection.first || Connection.create(player_id: 1, ip_address_id: 1)}
        let(:bank_account) {BankAccount.first || BankAccount.create(account_owner_id: 1)}
        let(:sell_offer) {SellOffer.first || SellOffer.create(seller_bank_account_id: 1, item_id: 1)}
        let(:buy_offer) {BuyOffer.first || BuyOffer.create(buyer_bank_account_id: 1, item_id: 1)}
        let(:owned_item) {OwnedItem.first || OwnedItem.create(owner_bank_account_id: 1, item_id: 1)}

      context 'associations' do
        it 'has ip addresses' do
          expect(player.ip_addresses.first).to eq(ip_address)
        end
        it 'has connections' do
          expect(player.connections.first).to eq(connection)
        end
        it 'has punishments' do
          expect(player.punishments.first).to eq(punishment)
        end
        it 'has a clan' do
          expect(player.clan).to eq(clan)
        end
        it 'has a bank account' do
          expect(player.bank_account).to eq(bank_account)
        end
        it 'has sell offers' do
          expect(player.sell_offers.first).to eq(sell_offer)
        end
        it 'has buy offers' do
          expect(player.buy_offers.first).to eq(buy_offer)
        end
        it 'has owned items' do
          expect(player.owned_items.first).to eq(owned_item)
        end
        it 'has a kingdom' do
          expect(player.kingdom).to eq(kingdom)
        end
      end

      context 'class methods' do
        # stuff
      end
    end
Jacob Crofts
  • 176
  • 2
  • 12
  • I found something that looks promising: a way to load seed data prior to running the tests (if I understand correctly) - might this be what I'm looking for? http://stackoverflow.com/questions/1574797/how-to-load-dbseed-data-into-test-database-automatically – Jacob Crofts Feb 18 '16 at 23:28
  • Hi, you should not need to seed the database - that would be the wrong way to fix this. in fact I think there's a disconnect here about what sort of data you need for tests. You should only set up data for each individual test that is used in that individual test. the data should not hang around after one test to be used again in the next test - test-data is and should be ephemeral (ie after *every* test it gets destroyed and recreated). This is very important for testing as tests should run independently of each other for a whole host of reasons I wont' go into right here. – Taryn East Feb 19 '16 at 01:28
  • So the important question is: why do you think you need to do data this way? Can you show me an example of an actual test that is testing *your code* instead of *how the database works internally* (which shouldn't need testing, you should assume the database just works)? – Taryn East Feb 19 '16 at 01:29
  • Also: if you really want to test associations, have you looked at the `shoulda` gem ? It will have things like `expect(player).to belong_to(:bank_account)` – Taryn East Feb 19 '16 at 01:30
  • Finally: You don't need to do this in a test: `Player.first || Player.create...` you should *always* just use `Player.create` - this will Just Work(tm) and not create new ones over and over (and if it does, then you have a bigger problem that we need to sort out first). but OOC for other situations (not this one), have you looked into Rails' `first_or_create` method? – Taryn East Feb 19 '16 at 01:31
  • @TarynEast Hello, Taryn, and thank you for your advice. I was testing my database this way because I thought it was good practice. In previous projects (all two of them) I just opened the rails console and tinkered around with my associations until (for example) `Player.first.ip_addresses` returned an ActiveRecord collection instead of an error. I'm still very much a beginner, so stuff like name aliasing within through relationships I never seem to get right on my first go. I'll check out the `shoulda` gem. – Jacob Crofts Feb 19 '16 at 02:36
  • Sure thing... it's ok to tinker - just understand that this is not the sort of stuff you normally need to do, and you should probably remove it once you've checked your data is set up the way you like. `shoulda` is definitely a good place to start. You'll get the hang of it all pretty quick :) – Taryn East Feb 19 '16 at 04:37

0 Answers0