简体   繁体   中英

Why use Mocks and Stubs to test a Rails Application?

I am not asking for the definition of Test Doubles (mocks) and Receive (stubs). I got plenty of those from SO. I just don't see why there are needed in a test at all. From an Rspec example I was reviewing, the programmer used this:

it "allows setting responses" do
  dbl = double("Chant")
  allow(dbl).to receive(:hey!) { "Ho!" }
  expect(dbl.hey!).to eq("Ho!")
end

No matter how many times we run this specific example it will ALWAYS pass. It will never fail. And the purpose of testing is to determine if an example will pass or fail. So why even have a double at all, if it always going to pass?

Mocks and stubs are among can used when your test meets the boundries of you application or the object under test.

For example if you're testing object A which has a dependency on B you may choose to stub B if the behaviour of B is not relevant or setting up a B is costly.

They can be also be used to enforce determinism. For example:

class DiceRoll
  attr_accessor :value

  def initialize
     @value = (1..6).to_a.sample
  end
end

Here we might choose to stub out dice_roll.value so that we can specify deterministically what should happen in a class that consumes it. A common example of this is testing network failure in HTTP clients, which is hard to achieve unless you´re really fast at pulling the plug.

Stubs can be used to stub out configuration such ENV vars to test how components behave depending on external factors.

They can also be used to remove dependencies on external collaborators such as APIs, databases or even the file system.

A commonly used example is FactoryBot.build_stubbed which creates a model instance that acts like it has been persisted without actually touching the DB.

There is no inherent value in stubbing or mocking for the sake of it. They are tools that can be used to solve tricky situations or increase performance. Mocking should always be weighed against test acuity - which is how well your tests actually test your application.

This test indeed is not very useful. But imagine that you're testing, say, export generation functionality. To build export file you need to call an external service (like a database or an API). For the purposes of testing correctness of the generated content, you can assume that the service works as intended and returns a known-good well-formed response. That's where you stub/mock it.

In the context of Rails, stubbing/mocking are invaluable in the effort to adhere to a reasonable-looking test pyramid .

Take Rails controller tests, for example.

Rails controllers:

  1. receive request body
  2. (ideally) delegate the heavy-lifting associated with processing request to other objects
  3. respond to the request

Unit testing controllers would then involve documenting through tests that the controller responds favourably to a variety of request bodies -- all one should care about are the requests, and the responses of controller actions and the return value of the the objects that do the heavy lifting in step 2. , which one can easily achieve by mocking the objects in step 2. or by stubbing the response of some method calls. (As a prerequisite, I would ensure that the objects that do the heavy-lifting have unit tests of their own before mocking them away in the controller tests.)

Depending on your application, you may also decide to not write controller tests with mocks and instead write integration tests to also test the objects. This is sometimes the ideal approach, especially when the worker objects are themselves pretty light-weight. At the end of the day, I would try to ensure that I don't invert the testing pyramid, although there are probably cases in which it is okay to do so.

In model/service object tests, personally, I also like to not interact with databases if the operation is expensive and redundant.

The advantage of mocking is obvious in integration tests, particularly in a microservices based architectures, where your application has to do is communicate over networks, and it isn't concerned with how other services process requests. Being able to stub the response of other services is very important.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM