In object oriented programming classes call methods on other classes. While it’s important to test the integration between classes it is very useful to test them in isolation, simulating valid and invalid responses from the dependent objects.
As applications grow we usually create smaller classes that call each other. Let’s imagine class Foo that calls class Bar.
We want to thoroughly test Bar class:
Separately we want to test Foo class and make sure it can handle different responses from Bar:
What expect(Bar).to receive(:new).and_return(bar) does it is allows Foo.new.perform to execute but instead of calling real Bar class it uses double.
Controllers and form objects
For more realistic use case let’s imagine a system where user can subscribe/unsubscribe from various newsletters. Separately user can choose global unsubscribe. Once the user unsubscribes from specific newsletter we want to keep that record so we do not accidentally re-subscribe user.
Form objects can be a useful design pattern for handling complex user input. When user submits form via http://localhost:3000/unsubscribe/user_id we need to create/update records in UserNewsletter and update User.subscribed.
Here is the form object:
And basic UI:
We want to thoroughly test the form object by creating appropriate records and check that data is persisted in the DB.
In controller test we can mock Unsubscribe form responses and only check the HTTP status code.