Giter Club home page Giter Club logo

with's Introduction

With

HIGHLY EXPERIMENTAL!

Heavily inspired by both
context
by Jeremy McAnally and
context_on_crack
(as well as rspec_on_rails_on_crack)
by Rick Olson.

For some demo code see: runnable demo controller test.
Style and initial motivation: http://gist.github.com/30436.

In short the goal of this library is:

  1. setup preconditions for tests/assertions in a more flexible and concise way
  2. run as many assertions with common preconditions (setup/before) at once as possible

So it allows to write test/unit tests like this:


  describe 'POST to :create' do
    action { post :create, @params }
  
    with :login_as_admin do
      it_assigns :article

      it "succeeds", :with => :valid_article_params do
        it_redirects_to 'articles/1'
        # more assertions ...
      end
      
      it "fails", :with => :invalid_article_params do
        it_assigns_flash :error, :not_nil
        # more assertions ...
      end
    end
  
    with [:login_as_user, :no_login] do
      it_redirects_to '/login'
    end
  end

This piece of code will generate at least 4 tests:


  test_POST_to_create_with_login_as_admin_and_with_valid_article_params
  test_POST_to_create_with_login_as_admin_and_with_invalid_article_params
  test_POST_to_create_with_login_as_user
  test_POST_to_create_with_no_login
  # TODO test method names should include the assertion block names (e.g. "succeeds")

Shared context blocks can be setup like this:


  share :login_as_admin do 
    before { @controller.current_user = Admin.new }
  end
  
  share :valid_article_params do
    # could also use a tool like FactoryGirl, Mechanist etc.here
    before { @params = {'title' => 'article title', 'body' => 'article body'} } 
  end

Also, one can map a context name like :invalid_article_params to multiple
blocks. With will then expand them and create separate tests for
them.

E.g. with a definition like:


  # share multiple contexts with the same name:  
  share :invalid_article_params do
    before { @params = valid_article_params.except(:title) }
  end
  
  share :invalid_article_params do
    before { @params = valid_article_params.except(:body) }
  end
  
  # or register them at once:  
  share :invalid_article_params,
    lambda { before { @params = valid_article_params.except(:title) } },
    lambda { before { @params = valid_article_params.except(:body) } }

… it would generate two methods and test the actual assertions against both
invalid article params that are missing a title and those that are missing a
body.

Note that the second goal stated above (“run as many assertions with common
preconditions at once as possible”) also means that this does not follow the
one assertion per test
philosophy any more.

E.g. some pseudo code for the first generated method above would be:


  def test_POST_to_create_with_login_as_admin_and_with_valid_article_params
    # preconditions
    @controller.current_user = Admin.new
    @params = {'title' => 'article title', 'body' => 'article body'}
    
    # action
    post :create, @params
    
    # assertions
    it_assigns :article
    it_redirects_to 'articles/1'
  end

(You can still use the default test/unit setup method for setting
up common, expensive scenarios for the whole testcase.)

The reason for this choice is that tests will run much faster when multiple
assertions are validated against the result of one actual controller call (that
goes through routing, controller setup, filters, …) instead of running this
setup for every single assertion.

With this speed gain it is possible to run controller tests without heavy stubbing
and still have reasonable test execution times. So basically the tradeoff I
had in mind with this was: trade “real model usage” instead of heavy stubbing
(which I wanted to get rid of for my controller tests) for multiple assertions
per test (which I think still works fine for controller tests).

with's People

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.