diff --git a/README.md b/README.md index 4d11ed9..f50efe7 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ pairing with smart people at Hashrocket. For a steady stream of TILs, [sign up for my newsletter](https://crafty-builder-6996.ck.page/e169c61186). -_1699 TILs and counting..._ +_1700 TILs and counting..._ See some of the other learning resources I work on: @@ -1357,6 +1357,7 @@ If you've learned something here, support my efforts writing daily TILs by - [Create a CSV::Table Object](ruby/create-a-csv-table-object.md) - [Create A Hash From An Array Of Arrays](ruby/create-a-hash-from-an-array-of-arrays.md) - [Create Listing Of All Middleman Pages](ruby/create-listing-of-all-middleman-pages.md) +- [Create Mock Class That Can Be Overridden](ruby/create-mock-class-that-can-be-overridden.md) - [Create Named Structs With Struct.new](ruby/create-named-structs-with-struct-new.md) - [Create Thumbnail Image For A PDF](ruby/create-thumbnail-image-for-a-pdf.md) - [Decompose Unicode Character With Diacritic Mark](ruby/decompose-unicode-character-with-diacritic-mark.md) diff --git a/ruby/create-mock-class-that-can-be-overridden.md b/ruby/create-mock-class-that-can-be-overridden.md new file mode 100644 index 0000000..9852cc8 --- /dev/null +++ b/ruby/create-mock-class-that-can-be-overridden.md @@ -0,0 +1,85 @@ +# Create Mock Class That Can Be Overridden + +Let's say I've defined a `MockTwilioClient` class for my system tests so that +they don't have to actually make calls out to the Twilio API. + +```ruby +class MockTwilioClient + def send_sms_message + "MSG_SID_123" + end +end +``` + +Now, any test that is exercising behavior that uses those parts of the +`TwilioClient` can mock those calls in a predictable way. + +The above class always is successful when `send_sms_message` is called. What if +we want to simulate an error response? We need a way to override the client for +specific testing scenarios. + +Let's create a helper that can create `MockTwilioClient` instances, either as is +or with overrides. + +```ruby +def create_mock_twilio_client(&block) + if block_given? + Class.new(MockTwilioClient, &block).new + else + MockTwilioClient.new + end +end +``` + +If we pass it a block with specific method overrides, it will create a one-off +anonymous subclass of `MockTwilioClient` with that block which effectively +overrides the parent class's methods. + +We can put this to use like so: + +```ruby +require 'test_helper' + +class SomeSystemTest < SystemTestCase + class MockTwilioClient + def send_sms_message + "MSG_SID_123" + end + end + + def create_mock_twilio_client(&block) + if block_given? + Class.new(MockTwilioClient, &block).new + else + MockTwilioClient.new + end + end + + test "send message to customer" do + mock_client = create_mock_twilio_client + + TwilioClient.stub(:new, mock_client) do + # some action that uses `send_sms_message` + + # some assertions ... + end + end + + test "fail to send message to customer" do + mock_client = create_mock_twilio_client do + def send_sms_message + raise "Failed to send message" + end + end + + TwilioClient.stub(:new, mock_client) do + # some action that uses `send_sms_message` + + # some assertions ... + end + end +end +``` + +In the second test case, I override the _success path_ with a version of +`send_sms_message` that raises an error.