1

I've got some model code that calls to the database with a simple find():

@thing = Thing.find(id)

I have data seeded in the database for the test environment. If I open the console in test (rails c -e test), I can run Thing.find(1) and get a result fine, however when I run a test that calls the method shown above, it reports that it cannot find a record with the id of 1.

I assume I am misunderstanding the relationship between test seed data and the tests being run against that database. Why do I see seed sin the test DB but the test doesn't?

RedBassett
  • 3,469
  • 3
  • 32
  • 56
  • 3
    Are you sure it has the same ID? It's not a good idea to hard-code IDs in your tests because the auto-incrementer can sometimes make them different – max pleaner Jan 10 '21 at 22:30
  • In reality, the ID doesn't actually matter, just that a record is fetched when the method is called. That said, I could pull the ID from the record elsewhere to ensure it is the correct ID. But that still leaves my underlying question: Why does that ID return a record in the console but not in the test? – RedBassett Jan 11 '21 at 09:39
  • Is your test database wiped between runs? – max pleaner Jan 11 '21 at 17:53
  • I don't do anything to wipe it, but that is part of my question. Tests run too fast to run seeds between every run, but does the test suite do something to reset the DB to initial state? I can still see data in the DB in the test environment from the console, so if tests do wipe it at all they also put seeds back in. – RedBassett Jan 12 '21 at 01:02
  • I tried bypassing the hardcoded ID by instead referencing `Thing.first`, however that is coming back `nil`, so it does in fact seem like the seed data is not available to the test for some reason, even though it shows in the console for the test environment just fine. – RedBassett Jan 12 '21 at 05:26

1 Answers1

0

A more conventional way of doing this would be to create fixtures (or factories if using FactoryBot) and call these factories in your test setup. As previous answers have said, hardcoding test ID's will likely return RecordNotFound due to auto-incrementing.

kykyi
  • 375
  • 4
  • 10
  • The test ID is `1`. Are you saying that because of tests running in sequence the auto increment column would not be using that ID? If that is the case, that could be my problem. I am not using fixtures or a factory because this seed data is also used in production. While it's seeded in the test environment, it's actual data I use elsewhere. I could mock it with fixtures, but since I already load the seeds in both dev and prod, I set them to always run in any environment to ensure test looked as close to prod as possible. – RedBassett Jan 11 '21 at 09:43
  • 1
    I fixed the tests to user `Thing.first` and test against the ID field instead of using a hardcoded ID. `first()` is returning `nil`, so the issue does in fact seem to be no data available to the test. – RedBassett Jan 12 '21 at 05:25
  • Each test run is its own DB transaction, and any test setup is a nested transaction inside this. If the nested transactions do not violate DB constraints, they are committed and that is how data is available in test (so you can call ```Thing.create!``` then ```Thing.first``` and instantiate a ```Thing```), but as part of the test frameworks 'tear down', it will rollback (as opposed to commit) the outer transaction, essentially wiping the DB of any changes made in test. Reference: https://guides.rubyonrails.org/testing.html#testing-parallel-transactions – kykyi Jan 12 '21 at 08:03
  • 1
    Ok, thank you for breaking down exactly how the tests interact with the DB. Currently I have no setup, just the seeds. I'd like to be able to access the seeds, however for atomic testing, it would make sense to instantiate a specific record in setup just for testing against. – RedBassett Jan 12 '21 at 08:28