Categories: Web Dev Training

One Easy Way To Speed up your Rails Tests and RSpec

There comes a time in the life of every Ruby on Rails project where you and your team will end up with long running tests. Rails tests can contain factories, fixtures and lots of setup procedures before tests are executed, and all of these can contribute to major slowness in the test runs.

I’ve seen four ways of dealing with slow running tests in Rails:

  1. start deleting tests (or mark them as skip-able): the drawback is your test coverage drops and you may end up with more bugs
  2. use more integration tests rather than unit tests: this exercises a lot of code paths so test coverage won’t drop too much but in the end most developers will write integration tests that exercise the “happy path”
  3. Run your tests in parallel
  4. Run only the tests that were most likely to be affected by recent code changes

The latter two methods are much better than the first two.

My favourite so far is #3 because it still runs all of the integration and unit tests that you have but makes use of the fact that you can offload the work of running tests to multiple machines. Everyone now has access to multiple machines through AWS (Amazon Web Services) or Microsoft Azure or RedHat’s cloud. You can even run tests in parallel on your local development machine.

Run Your Ruby on Rails Tests In Parallel

The idea is that each test file will be run in separate processes.

If you have 5 tests that have a duration 2 minutes, in sequential runs it will take 10 minutes to run the whole test suite. If you have 5 processes available for parallel runs, it will only take 2 minutes to run the whole test suite.

That’s a huge difference and means you can make 30 test runs in an hour rather than 6 test runs.

Splitting RSpec test files into multiple files

However, some of your Rails tests may take longer; within the spec you could have multiple test cases and contexts that are taking too long. For example, one test context with a few tests could be taking 1 minute while the rest of the test cases in that file only take 10 seconds. At that point, you can split the long-running test context into multiple files.

Here’s an example of how that might look like:

# spec/my_controller_spec.rb
describe MyController do
  context 'Slow tests' do
    it 'runs slowly #1' do
      # ...
    end
    it 'runs slowly #2' do
      # ...
    end
  end

  context 'Faster part of the test suite' do
    it 'runs in 10 seconds or less' do
      # ...
    end
  end
end

And now here’s how we could split that controller rspec test file into multiple files.

# spec/my_controller_spec.rb
describe MyController do
  context 'Faster part of the test suite' do
    it 'runs in 10 seconds or less' do
      # ...
    end
  end
end

# spec/my_controller_slow_1_spec.rb
describe :MyControllerSlow1 do
  def self.described_class
    MyController
  end

  include_context 'my controller helpers'

  it 'runs slowly #1' do
    # ...
  end
end

# spec/my_controller_slow_2_spec.rb
describe :MyControllerSlow2 do
  def self.described_class
    MyController
  end

  include_context 'my controller helpers'

  it 'runs slowly #2' do
    # ...
  end
end

The reason this works is because we override the class method described_class. This method is used by the rspec-rails extensions that make it easier to test Rails classes with RSpec.

By using shared contexts and helpers and by splitting files, you can optimize your Rails tests even further.

(If you liked this article, I have written about using mocks with Django and Python unit and integration tests and using Protractor with AngularJS and how you can take screenshots with Selenium during test runs.)

Categories: Software Development

Django Unit Testing with Mocks

Here I’m going to talk about how to use mocks when writing unit tests for Django, the Python-based web framework. Using Django test mocks has really opened my eyes on how to write much better unit tests. Previously, and in some cases still do when using 3rd party services, I would use fake API servers to serve fake data for testing end to end. With the mock library, I can easily mock out server responses in Django tests.
Continue reading “Django Unit Testing with Mocks”

Categories: AngularJS, Web Dev Training

Unit Testing in AngularJS

The modern way of development is to build and deliver web apps that include automated unit test suites. These automated tests exercise your web app to make sure that it works and doesn’t have any bugs. Tests give you the confident to say to your client or project manager or customer, yes we have the right features and yes they all work.

“Test-driven development is a set of techniques that any software engineer can follow, which encourages simple design and test suites that inspire confidence…following these two simple rules can lead us to work much more closely to our potential.

  • Write a failing automated test before you write any code.
  • Remove duplication.”

Kent Beck, Test Driven Development

Unit Tests

Unit testing is essential and of course, AngularJS lets you do some unit testing. In fact, it was built from the ground-up to co-operate with unit testing by using dependency injection.

One of the better tutorials on fully testing your AngularJS app is Full-Spectrum Testing With AngularJS and Karma.

To begin unit testing AngularJS, you need the following:

  • Karma test runner
  • Jasmine or Mocha/Chai test frameworks
  • Sinon for mocking/spies/stubs

The Karma test runner will run whatever tests you have. The Jasmine test framework lets you define tests and has assertions (such as myValue.is.expected.toBe(3)). Personally, I prefer the Mocha framework since it only defines tests, and lets you use whatever assertion library you want to use such as Chai, it also has lots of nice features.

A classic on unit testing is Test Driven Development: By Example, it’s by Kent Beck who was one of the founders of the Extreme Programming movement.

Mocking Dependencies for Integration and Unit Testing AngularJS

Sometimes when you’re writing a test, you want to make sure that your service or provider is making the right calls to another service. The way to do this is with mocks. Mocks are fake objects that keep track of which methods were called on them.

Mocks are not essential for writing tests, but there are cases where they do help. When you’re writing a controller that connects to your web app’s REST API, you want to make sure that it calls methodX and methodY. By creating a mock service and registering it with AngularJS, you can write a unit test that makes sure those two methods have been called. When using external 3rd party REST APIs, you may want to mock the $httpBackend to make sure the right calls are being made and the correct responses are returned.

Sinon is valuable for defining mocks. It lets you create method stubs and it lets you spy on method calls.

ng-modules

Find more modules on ngmodules.org

News

AngularJS Meetups

Categories: Software Development

End to end tests posing as unit tests

I’ve been reading the excellent book The Art of Agile Development, I started to think more about why Test Driven Development is important and how it affects how you write code.

Using some of the 20%/practice group time we have at work, I started to review my own code to see if I’m living up to the test-driven development methodology. Are there enough unit tests? Yes, there were, code coverage was over 70% in most cases and with a little work I got it to 100% coverage for the most important code (the views and models). Then I started to noticed something about my tests…they’re not unit tests at all! They’re end to end tests! What Django calls unit testing is actually an end to end test. We’re testing from one end, the website, to the other end, the database. This means that we’re testing each view to ensure that it includes the right data, that it uses the right templates, etc. Then we’re testing interaction and checking the results in the database. Continue reading “End to end tests posing as unit tests”