FullStack Labs

Please Upgrade Your Browser.

Unfortunately, Internet Explorer is an outdated browser and we do not currently support it. To have the best browsing experience, please upgrade to Microsoft Edge, Google Chrome or Safari.
Upgrade
Welcome to FullStack Labs. We use cookies to enable better features on our website. Cookies help us tailor content to your interests and locations and provide many other benefits of the site. For more information, please see our Cookies Policy and Privacy Policy.

Mocking Server Responses in Capybara

Written by 
Andres Pabon
,
Senior Software Engineer
Mocking Server Responses in Capybara
blog post background
Recent Posts
From Recommendations to Immersive Try-Ons: AI's Role in Consumer Goods
Mastering Agile Project Management: Navigate Success with a Large Team
Driving Excellence in QA: Continuous Improvement and Postman Best Practices

When writing tests in Capybara, you often want to isolate specific portions of a class. You might want to create a unit test, or perhaps you just don’t have the required connection access to pull data required by a class method.

Table of contents

Within a Capybara test, it is possible to mock the response of a controller method before it is instantiated. So, for example, you can have this Ruby class:


class Employee
 include AssetsUrl
 
 attr_accessor :name, :email, :picture_id, :proficiencies
  def initialize(params = {})
   @name = params.fetch(:name, '')
   @email = params.fetch(:email, '')
   @picture_id = params.fetch(:picture_id, '')
   @proficiencies = params.fetch(:proficiencies, {})
 end
  def picture_url
   AssetsUrl.get_main_url + '?img=' + @picture_id
 end
 
 def get_proficiency(proficiency)
   @proficiencies[proficiency] || 'none'
 end
 
 def set_proficiency(proficiency, value)
   @proficiencies[proficiency] = value
 end
end

Notice how picture_url depends on an external class AssetsUrl to get the main part of an image URL (perhaps all of your employee profile pictures reside in the same external server); but that class might not be available in your unit test scope (or available within your UI test permissions), so you might want to mock that response in order to proceed with your tests.

You can mock any calls to picture_url completely by using allow_any_instance_of to force any call to it responding what you need, by adding this to your Capybara test:


before do
 allow_any_instance_of(Employee).to(
   receive(:picture_url).and_return('https://fullstacklabs.co/images')
 )
end

The before definition instructs the Capybara test set to run this part before any proper test (as defined by any it block), and can be included within either a context or a describe block. The allow_any_instance_of statement allows you to mock a class before it’s instantiated, and you can specify the method you want to mock using receive (in this case, picture_url) and the response you want the method to return.

You could also mock AssetsUrl, so that Employee still calls for it, but its response will be the one you actually want to mock, like so:


before do
 allow_any_instance_of(AssetsUrl).to(
   receive(:get_main_url).and_return('https://fullstacklabs.co/images')
 )
end

Furthermore, you could also mock the response for a method based on the parameters it’s being called with. Suppose you had a more generic get_url (instead of get_main_url) defined in AssetsUrl, which receives work_area, an area identifier that determines the asset’s base URL. Something like this:


class AssetsUrl
 # some code...
 def get_url(work_area)
   # some logic dependant on the specified work area
 end
 # ...more code
end

You might then want to test Employee for a particular work area. For example, you might want to test the Employee class for a worker in development, but then use the same test set to actually fetch the real data for the sales work area. To do so, you want to change them before the statement to something like this:


before do
 allow_any_instance_of(AssetsUrl).to(
   receive(:get_url)
     .with(:development)
     .and_return('https://fullstacklabs.co/development/images')
 )
end

By using the with method, you can instruct allow_any_instance_of to be called only when invoked with that particular parameter, just as you did with the receive method before. Whenever AssetsUrl gets invoked with any method other than get_url, or whenever get_url is called with a parameter other than developing, then the main definition will be executed (with no mocking behavior).

Finally, if you want to reset the original behavior for a particular test, you can always overwrite the mocking behavior with the original behavior using this line:


allow_any_instance_of(AssetsUrl).to(
 receive(:get_main_url).and_call_original
)

This line will just call the original method, ignoring any mocks defined in a before block.

Andres Pabon
Written by
Andres Pabon
Andres Pabon

No longer with FSL

From a very young age, I have always loved computers. My dad worked as a software developer, and I started learning the trade when I was only 6 years old. That desire to build software never faded away. I enjoy being able to model real world problems through mathematics and implement useful solutions. I have over 19 years of development experience, mainly building web applications using the ASP.NET framework, JavaScript and Node.js architectures, and several SQL-based and non-relational databases like MongoDB. I'm determined, friendly, and responsible, and I enjoy playing games of all kind (board, role-playing, video), cooking, and reading.

People having a meeting on a glass room.
Join Our Team
We are looking for developers committed to writing the best code and deploying flawless apps in a small team setting.
view careers
Desktop screens shown as slices from a top angle.
Case Studies
It's not only about results, it's also about how we helped our clients get there and achieve their goals.
view case studies
Phone with an app screen on it.
Our Playbook
Our step-by-step process for designing, developing, and maintaining exceptional custom software solutions.
VIEW OUR playbook
FullStack Labs Icon

Let's Talk!

We’d love to learn more about your project.
Engagements start at $75,000.

company name
name
email
phone
Type of project
How did you hear about us?
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.