mercredi 22 juin 2016

Reducing bloat in testing patterns with cancan and RSpec

I've got a fairly large and complex user-permissions scheme using cancan that has been built on a set of user-access-levels I'm calling 'tiers'. Right now there are 6 tiers and we may add more in the future. Each tier of user has access to different features and in some cases the branching gets quite complex. With each new tier, the complexity grows exponentially.

I'm testing this with RSpec and in some cases testing has become a problem, particularly with controller/integration tests. I'm unit-testing the Ability model, and that's pretty straight-forward, following the recommendations in the cancan wiki: http://ift.tt/28OavS2 . But, integration testing has quickly become bloated and I would like to try to minimize the bloat without completely disregarding tiers and permissions in my integration tests.

I'm looking for patterns that will allow integration testing to continue taking tier-based permissions into account, while minimizing the amount of bloat.

Some of my controller tests are starting to look a lot like this:

    allow(controller).to receive(:can?).with(:read, :some_feature).and_return(true)
    allow(controller).to receive(:can?).with(:read, :some_other_feature).and_return(true)
    allow(controller).to receive(:can?).with(:read, :yet_another_feature).and_return(false)
# ... lots of other stubs

As we continue to add restricted features, this just gets worse and worse. I'm thinking about some other patterns like defining a bunch of factories for each user type and setting up each controller with branching tests for each type, but I'm not yet sure that's going to be any better.

I imagine that other folks must have run into issues like this before and am just hoping someone has some creative ideas about how to reduce the amount of stubbing that I'm doing, or has found a pattern that they like that provides good test coverage without so much bloat. Just testing the abilities themselves without doing any integration testing feels insufficient to me but maybe that's the best answer!

Aucun commentaire:

Enregistrer un commentaire