perpetuum mobile
05. 08. 2014. bdd / tdd * rspec * ruby gem

Rspec gem

TDD Antipatterns

  • It is better to write a new test case method to test another/distinct feature/functionality rather then to add a new assertion to an existing case.
  • if different values are being tested, each should have its own test case with a clear description

Resources:

  • https://semaphoreapp.com/blog/2014/06/24/tdd-antipatterns-the-free-ride.html
  • https://semaphoreapp.com/blog/2014/07/10/tdd-antipatterns-local-hero.html
  • http://stackoverflow.com/questions/333682/unit-testing-anti-patterns-catalogue

Rails testing antipatterns

  • Using fixtures; solution -> factories
  • Factories pulling too many dependencies
  • Factories that contain unnecessary data
  • Factories depending on database records (breaks CI)
  • Creating records when building would also work
  • All model, no unit tests
  • Using let to set context; solution -> using before blocks to initialize data instead
  • Incidental database state
  • Skipping controller tests; controller should be limited to:

  • Extracting parameters
  • Checking for permissions, if necessary
  • Directly calling one thing from the inside of the app
  • Handling any errors, if they affect the response
  • Rendering a response or redirecting

  • Creating records in controller tests; solution -> using mocks and test doubles
  • No controller tests, only integration
  • Complex controller spec setup

Resources:

  • https://semaphoreapp.com/blog/2014/01/14/rails-testing-antipatterns-fixtures-and-factories.html
  • https://semaphoreapp.com/blog/2014/01/21/rails-testing-antipatterns-models.html
  • https://semaphoreapp.com/blog/2014/02/11/rails-testing-antipatterns-controllers.html

Testing an OAuth flow

with Cucumber:

Before("@omniauth_test") do
  OmniAuth.config.test_mode = true

  OmniAuth.config.mock_auth[:github] = {
    "uid" => "1",
    "provider" => "github",
    "info" => { "nickname" => "darkofabijan", "name" => "Darko Fabijan" },
    "credentials" => { "token" => "63146da137f3612f..." }
  }
end

After("@omniauth_test") do
  OmniAuth.config.test_mode = false
end

Resources

  • https://semaphoreapp.com/blog/2014/03/18/managing-externals-in-ruby-tests.html

Shared examples

Names of files containing shared examples should not end in _spec, otherwise they will get executed on their own when rspec is run.


Matching arrays

expect(resource_hash.keys).to include(*fields)
expect(one_array).to match_array other_array

#### Adding custom message to expectation

expect(sent_value).to eq(db_value), lambda { "expected #{field} to be #{db_value}, got #{sent_value}" }

 Resources

General resources

Unsorted & unprocessed sources

TODO

Fast Rails Tests: http://vimeo.com/30893836