Skip to content

Chapter II - Model and Validation Specs

(avr. time for this chapter: 1 day)

Model specs are the foundation of your test suite. They test the business logic, validations, associations, and methods of your models. These are unit tests—they test small, isolated pieces of code.

In this chapter, you will learn how to properly test your Ebook, User, and Purchase models, including validations, associations, callbacks, and custom methods.

Testing Validations

Rails validations ensure data integrity. Your tests should verify that these validations work as expected.

Steps to implement:

  1. Create tests for presence validations on your Ebook model:
  2. Test that an ebook is invalid without a title
  3. Test that an ebook is invalid without a price
  4. Test the error messages are correct
  5. Create tests for uniqueness validations on your User model:
  6. Test that duplicate emails are rejected
  7. Create tests for format validations:
  8. Test valid and invalid email formats for User
  9. Create tests for numericality validations:
  10. Test that ebook price must be greater than zero
  11. Test that price cannot be negative
  12. Create tests for inclusion validations:
  13. Test that ebook status must be one of: draft, pending, live

Reference: Rails Testing Guide

Testing Associations

Your ebook application has relationships between models. Test that these associations are properly defined.

Steps to implement:

  1. Test belongs_to associations:
  2. Ebook belongs to User (seller)
  3. Purchase belongs to User (buyer)
  4. Purchase belongs to Ebook
  5. Test has_many associations:
  6. User has many Ebooks (as seller)
  7. User has many Purchases (as buyer)
  8. Ebook has many Purchases
  9. Test has_many :through associations (if applicable):
  10. User has many purchased ebooks through Purchases
  11. Verify dependent destroy behavior:
  12. When a user is deleted, what happens to their ebooks?

Tip: You can use the shoulda-matchers gem to simplify association tests

Testing Scopes

Your ebook application should have scopes for filtering ebooks by status.

Steps to implement:

  1. Test the published scope (ebooks with status 'live'):
    describe '.published' do
      it 'returns only live ebooks' do
        draft_ebook = Ebook.create(title: "Draft", status: :draft, ...)
        live_ebook = Ebook.create(title: "Live", status: :live, ...)
    
        expect(Ebook.published).to include(live_ebook)
        expect(Ebook.published).not_to include(draft_ebook)
      end
    end
    
  2. Test the by_seller scope:
  3. Create ebooks for different users
  4. Verify the scope returns only ebooks from a specific seller
  5. Test scope chaining:
  6. Example: Ebook.published.by_seller(user)

Testing Instance Methods

Your models should have custom methods. Test them thoroughly.

Steps to implement:

  1. Test User status methods:
  2. user.enable! should set status to enabled
  3. user.disable! should set status to disabled
  4. user.enabled? should return true/false
  5. Test Ebook status transition methods:
  6. ebook.publish! should change status from pending to live
  7. ebook.submit_for_review! should change status from draft to pending
  8. Test ebook statistics methods (if implemented):
  9. ebook.view_count
  10. ebook.purchase_count

Testing Callbacks

Your ebook application likely has callbacks for sending emails and tracking statistics.

Steps to implement:

  1. Test after_create callback on Purchase:
  2. Verify that purchase creation triggers the notification logic
  3. Test before_save callbacks:
  4. If you normalize data (e.g., downcase email), test it
  5. Test callbacks that update statistics:
  6. When a purchase is created, ebook statistics should update

Warning: Avoid over-testing callbacks. Test the behavior, not the implementation.

Exercise

Apply these concepts to your ebook application:

  1. Write comprehensive model specs for Ebook:
  2. Test all validations (title presence, status inclusion, price numericality)
  3. Test the association with User (seller)
  4. Test status transition methods
  5. Test scopes: published, by_seller, draft, pending

  6. Write comprehensive model specs for User:

  7. Test email format validation
  8. Test the enable/disable status methods
  9. Test associations with ebooks (as seller)
  10. Test associations with purchases (as buyer)

  11. Write specs for the Purchase model:

  12. Test the association between buyer, seller, and ebook
  13. Test that a purchase records the correct price
  14. Test any callbacks that trigger notifications