TTNT: Test This, Not That!

Build Status Coverage Status Code Climate Dependency Status

Developing under Google Summer of Code 2015 with mentoring organization Ruby on Rails.

Full proposal of this project is here (might be obsolete in some ways, read this README about this project itself rather than the proposal).

Goal of this project

rails/rails has a problem that CI builds take hours to finish. This project aims to solve that problem by making it possible to run only tests related to changes introduced in target commits/branches/PRs.

Approach

The idea is based on Aaron Patterson's article "Predicting Test Failures". This program uses differences in code between base commit (say, the latest commit of master branch) and target commit (say, HEAD of your feature branch) to calculate which test cases are affected by that change.

Terminology

  • test-to-code mapping
    • mapping which maps test (file name) to code (file name and line number) executed on that test run for a given commit
    • this will be used to determine tests that are affected by changes in code
  • base commit
    • the commit to which the tests you should run will be calculated (e.g. the latest commit of master branch)
    • this commit should have test-to-code mapping
  • target commit
    • the commit on which you want to select tests you should run (e.g. HEAD of your feature branch)
    • this commit does not have to have test-to-code mapping

Current Status

This project is still in an early stage and we are experimenting the best approach to solve the problem.

Currently, this program does:

  • Generate test-to-code mapping for a given commit
  • Given base commit and target commit, output test files you should run

Roadmap

Roadmap is under construction.

Installation

Add this line to your application's Gemfile:

gem 'ttnt'

And then execute:

$ bundle

Or install it yourself as:

$ gem install ttnt

Define Rake tasks

TTNT allows you to define its tasks according to an existing Rake::TestTask object like:

require 'rake/testtask'
require 'ttnt/testtask'

t = Rake::TestTask.new do |t|
  t.libs << 'test'
  t.name = 'task_name'
end

TTNT::TestTask.new(t)

This will define 2 tasks: ttnt:task_name:anchor and ttnt:task_name:run. Usage for those tasks are described later in this document.

You can also instantiate a new TTNT::TestTask object and specify certain options like:

require 'ttnt/testtask'

TTNT::TestTask.new do |t|
  t.code_files = FileList['lib/**/*.rb'] - FileList['lib/vendor/**/*.rb']
  t.test_files = 'test/**/*_test.rb'
end

You can specify the same options as Rake::TestTask. Additionally, there is an option which is specific to TTNT:

  • code_files
    • Specifies code files TTNT uses to select tests. Changes in files not listed here do not affect the test selection. Defaults to all files under the directory Rakefile resides.

Requirements

Developed and only tested under ruby version 2.2.2.

Usage

Produce test-to-code mapping for a given commit

If you defined TTNT rake task as described above, you can run following command to produce test-to-code mapping:

$ rake ttnt:my_test_name:anchor

Select tests

If you defined TTNT rake task as described above, you can run following command to run selected tests.

$ rake ttnt:my_test_name:run

Options

You can run test files one by one by setting ISOLATED environment variable:

$ rake ttnt:my_test_name:run ISOLATED=1

With isolated option, you can set FAIL_FAST environment variable to stop running successive tests after a test has failed:

$ rake ttnt:my_test_name:run ISOLATED=1 FAIL_FAST=1

Current Limitations

  • Test selection algorithm is not perfect yet (it may produce false-positives and false-negatives)
  • Only supports git
  • Only supports MiniTest
  • Only select test files, not fine-grained test cases
  • And a lot more!

This gem can only produce test-to-code mapping "from a single test file to code lines executed" (not fine-grained mapping "from a single test case to code lines executed"). This is due to the way Ruby's coverage library works. Details are covered in my proposal.

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake test to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/Genki-S/ttnt. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

I really :heart: getting interesting ideas, so please don't hesitate to open a issue to share your ideas for me! Any comment will be valuable especially in this early development stage. I am collecting interesting ideas which I cannot start working on soon here at Trello.

License

The gem is available as open source under the terms of the MIT License.