Search⌘ K
AI Features

Fully Implement and Test Business Logic

Explore how to fully implement and test business logic within a Ruby on Rails app by focusing on validation, mailer integration, and test-first workflow. Understand the importance of testing real-world scenarios involving widget status, pricing, and email notifications to ensure reliable, maintainable code.

We'll cover the following...

Testing the business logic

With our seam now defined, we find it easier to switch to a test-first workflow. The logic we have to build is pretty complex, and this will require a lot of tests.

  • Create a valid widget for a manufacturer created three months ago. Check that the status is “Fresh” and that no emails were sent.
  • Create a valid widget with a price of $7,500.01 and make sure the finance staff was emailed.
  • Create a valid widget with a manufacturer created 59 days ago and make sure the administrative staff was emailed.
  • Create invalid widgets and check the errors. For these cases, we don’t need to have one test for every single validation, though each does need testing:
    • Widgets missing a name, price, and manufacturer.
    • Widget with a four-character name.
    • Widget for an old manufacturer with a price of $99.
    • Widget with a price over $10,000.
    • Widget with a price of $0.

For the sake of brevity, we won’t implement all of these, but we will implement a few that allow us to see the effect of Rails validations and mailers on our implementation and tests.

Let’s start with the basic happy path.

Ruby
# test/services/widget_creator_test.rb
require "test_helper"
class WidgetCreatorTest < ActiveSupport::TestCase
setup do
@widget_creator = WidgetCreator.new
@manufacturer = FactoryBot.create(:manufacturer,
created_at: 1.year.ago)
FactoryBot.create(:widget_status)
end
test "widgets have a default status of 'Fresh'" do
result = @widget_creator.create_widget(Widget.new(
name: "Stembolt",
price_cents: 1_000_00,
manufacturer_id: @manufacturer.id
))
assert result.created?
assert_equal Widget.first, result.widget
assert_equal "Fresh",result.widget.widget_status.name
end
end

This test should fail because we’re using whatever status is returned by WidgetStatus.first and not looking for one named “Fresh”.

Shell
bin/rails test test/services/widget_creator_test.rb || echo \
Test Failed
Running 1 tests in a single process (parallelization thresho…
Run options: --seed 19750
# Running:
Failure:
WidgetCreatorTest#test_widgets_have_a_default_status_of_'Fre…
Expected: "Fresh"
Actual: "maiores"
rails test test/services/widget_creator_test.rb:10
Finished in 0.405940s, 2.4634 runs/s, 7.3902 assertions/s.
1 runs, 3 assertions, 1 failures, 0 errors, 0 skips
Test Failed

We could fix this by naming the status we’re ...