Unit testing models with relationships between tables.

Hi,

I'm quite new to Rails but even newer to the idea of unit testing as
all the things I have done so far have been relatively small and so I
haven't bothered with unit tests. I'm just embarking on a much bigger
project and wanted some advice as to testing strategies.

I've been following the testing chapter in Agile Web Development With
Rails by the Pragmatic Programmers and I've been getting on ok with
that but I'm not sure how to test models that have relationships
between them.

For instance I have one model, ModelA say that belongs to another,
ModelB. I would like to use fixtures to preload some data; how do I
get the unit test for ModelA to load the fixture data for ModelB so
that I can perform the tests with the table dependencies in place? How
do I specify the foreign key value in the ModelA fixture so that it
refers to a record in ModelB?

What are the strategies when it comes to testing models with
relationships between tables? Do you just test as if there was no
relationship and use dummy values for foreign key fields or should the
relationships also be tested?

Also on a separate note, is there any point testing all the default
validations implemented by rails when they are themselves tested as
part of the rails framework?

Thanks in advance,
Toby

tobyclemson@gmail.com wrote:

I'm quite new to Rails but even newer to the idea of unit testing as
all the things I have done so far have been relatively small and so I
haven't bothered with unit tests. I'm just embarking on a much bigger
project and wanted some advice as to testing strategies.

Read everything I wrote over the past decade (including the comics) (-;

For instance I have one model, ModelA say that belongs to another,
ModelB. I would like to use fixtures to preload some data; how do I
get the unit test for ModelA to load the fixture data for ModelB so
that I can perform the tests with the table dependencies in place?

In the fixtures, specify low numbers for each item's id. Then copy the
matching numbers into other fixtures, so model_b_id: 2 refers to the
model_bs.yml with id: 2.

(This data duplication is not DRY; this is a known issue with fixtures
that someone might fix someday.)

How
do I specify the foreign key value in the ModelA fixture so that it
refers to a record in ModelB?

Then put fixtures :model_as, :model_bs in the top of your test suite,
and test like this:

   ma = model_as(:my_model_a)
   assert_equal 'foo', ma.model_b.name

That's it. The .model_b spontaneously populates when you call it.

What are the strategies when it comes to testing models with
relationships between tables? Do you just test as if there was no
relationship and use dummy values for foreign key fields or should the
relationships also be tested?

You need tests that resist bugs when you refactor your code. (This
makes refactoring easier, which makes your initial design less
important!)

The best way to test is "test first", so you write a test that fails
because your model_a can't do something yet. Then you upgrade model_a
to pass the test. If model_a requires a model_b to get its job done,
then the test will check that the job is done, and this forces model_a
and model_b to have some relationship.

Done right, you won't test the navigation itself between A and B. So
you are free to refactor that navigation (such as a migration that
converts has_one to has_many), and if the test still passes, then A
and B still get their job done.

A test case should follow the AAA pattern:

   def test_case
       a = model_as(:my_a) # Assemble test targets
       q = a.perform # Activate the target method
       assert_equal 42, q # Assert the result
   end

Most tests should call a .perform method that actually does something.
The original rule for this was "don't test getters and setters". That
means don't test trivial methods that merely fetch data. These include
your has_many relationships. Only test methods that add business value
to your app, and these methods will test the getters and setters for
you.

Also on a separate note, is there any point testing all the default
validations implemented by rails when they are themselves tested as
part of the rails framework?

Are you going to refactor the rails framework?