← Back to Upcase

Some question on good practices/assumptions

(bloodycelt) #1
  1. If I use Capybara 2, I should use request specs instead of integration specs correct?
  2. Is it a good practice to just mock current_user to return a Factory so I don’t have to deal with the headaches of oauth and logging in, and browser session headaches?

(Uģis Ozols) #2

That’s what I would do because I wouldn’t want to test that behaviour in every spec which involves having a current_user.

(bloodycelt) #3


Also I have been googling. Apparrently, and maybe I am wrong here. But it seems that what would go in the tutorial for integration specs are now called feature specs which use capybara.

Request Specs still call the full Rack stack, but don’t use capybara, it seems more for JSON API testing, and I think fall under the category of unit testing?

(Joe Ferris) #4

We generally use capybara and “feature specs” for high-level testing. You can see our conventions around naming and organization in our guides. We write specs using capybara’s feature DSL and put them in spec/features.

The Code Climate blog had a good post on testing called The Rails Testing Pyramid. The basic idea is that integration tests (usually capybara specs in Rails) are slower and harder to maintain, so it’s recommended to keep a smaller number of those and rely on faster, smaller unit specs for the bulk of your tests.

I use request specs in spec/requests for odd situations, such as testing redirects across domains or SSL rules. These can be difficult to test in isolation, because there are frequently a number of important moving parts. However, they’re also difficult to test using capybara, because most capybara drivers will actually attempt to use the hosts and protocols from your tests. Except for these odd situations, though, I’ll generally use capybara in spec/features or a unit test in spec/models, spec/controllers, spec/views, or somewhere else.

For logging in specifically, I think it can be worth it to have one sign up and sign in scenario in capybara, especially if you have any custom onboarding workflows, but most tests should not go through the sign up or sign in forms. We have middleware in Clearance for doing this, and Devise has a wiki page on testing with Capybara.

(bloodycelt) #5

OK, great so the integration specs in the workshop go in specs/features with capybara 2/rspec 2.

On the other note: I agree, however I don’t use Clearance or Devise. So I figured mocking current_user was a decent universal solution, as in most cases that’s all that matters is: does current_user return a user object.

(Luís Ferreira) #6

@jferris If you see capybara specs as integration test in Rails, what are component tests and system tests?

(Joe Ferris) #7

There are a number of testing terms, such as “integration,” “functional,” “acceptance,” “component,” and “system” that are not used consistently throughout the programming community. It’s difficult to figure out who coined most of these terms, and it’s even harder to prove that there’s a canonical definition.

I don’t find it useful to attempt to sort tests into strict categories; however, I do find it useful to use a variety of tools and angles to test applications.

The style used to test something ranges from completely integrated to completely isolated. Most tests don’t touch either extreme; they just trend towards one pole or another.

In general, as your tests become more integrated, meaning that they test more components working together in a realistic fashion:

  • They will make your production code more bug-free.
  • They will be easier to write.
  • They will run slower.
  • They will be harder to maintain.
  • They will not improve your production code.

In general, as your tests become more isolated, meaning that they test fewer components more directly:

  • They will make your production code easier to write.
  • They will improve the design of your individual components.
  • They will run faster.
  • They will be easier to maintain.
  • They will not be effective at catching regressions.
  • They will be harder to write.

As a tool, capybara can’t really be used to write unit tests. It requires a rack application, and it will be easiest to use when most of your components are actually working together. This is because it’s entirely UI-driven. Given that, we favor integration-style tests with capybara.

The rest of our tests usually trend more towards isolation, but some could be regarded as “component tests,” because:

  • They frequently leave the database unstubbed, particularly for model tests.
  • They usually don’t stub out or inject all of their collaborators. For example, our controller and view tests generally use actual model instances rather than pure stubs.

In summary:

We try to write a few, high-level tests using capybara from the perspective of many components working together, which we call integration tests. We use these to determine which components are necessary for high level requirements and to prevent regressions.

We write a lot of low-level unit tests testing as few components as possible, which we call uint tests. We use these to fuel our TDD process, improve the design of our code, and provide a reasonably fast test suite which will catch most major mistakes.

(Luís Ferreira) #8

Thanks for the response, I agree that it is much easier to lot at tests as part of a spectrum from completely integrated to completely isolated.

As for:

That means you don’t use mocks at all, or do you find they are useful in some cases?

(Joe Ferris) #9

We use mocks a lot, but I’ve found them difficult to use when other Rails components are involved.

For example, it’s very difficult to build a pure mock that will work with methods like url_for, redirect_to, or render, because the API expected by ActiveModel is large and involves class methods. For that reason, we generally use build_stubbed from FactoryGirl for models, but we’ll use pure mocks for other objects.

(Luís Ferreira) #10

Ok, I think what you’re saying matches what Gregory Moeck says in his ruby conf talk.

The gist of it is that testing state is good for procedural code (such as most of the rails framework stuff) and that mocks are good for testing pure OO code.

Does that make sense?

(Joe Ferris) #11

Yes, it does. Just to make sure we’re on the same page, what I’m saying is:

Testing state works well for Value Objects, Models, and other objects that tend to have a lot of query methods. It also works well when doing capybara testing, as you’re forced to observe results in the UI layer in those cases.

Using mock expectations works well for Tell, Don’t Ask-style code that contains command methods.

Most code, especially when separating concerns using MVC, will contain a mix of both kinds of objects, as well as objects that have both command and query methods, in which case you’ll have to feel around to see what’s easiest to test.