- Your Name: Genki Sugimoto
- Email Address: [email protected]
- GitHub Username: Genki-S
- Twitter Username: @GenkiSugimoto
- IM Address: None
- IRC Nickname: None
- Webpage/Blog: http://genkisugimoto.com
- College/University: Waseda University
- Subject/Major: Computer Science, Software Engineering
PickyTest (, PickeySpec, DiffTest, DiffSpec, or much cooler names I get along the project)
Run tests you should run, omit tests which is not related to your changes.
This project tries to determine which test should be run for a given commit based on changes introduced since the base commit (likely to be the latest commit on master branch). It maintains the data of relationships between application code and test cases, for example, "line 10 of a.rb
is executed by test cases A, B, and C". In this way, when a commit which changes line 10 of a.rb
is introduced, we know we should run test cases A, B, and C (and more, based on other changes). Using this, we can skip test cases which is not influenced by changes introduced.
We call this relationships "code-to-test mappings" later in this document.
The idea will be mostly the same as Predicting Test Failures | Tenderlovemaking. Only my project will be available for users with much easier way (by installing a gem and writing some setup code).
- This has been my area of interest
I am majoring in software engineering and the productivity in software engineering has been my interest for a long time. My dissertation is named "Improving Fault Localization Based on Dynamic Slicing using Additional Assertions", in which I used dynamic slicing (which can determine which lines of code had influence on certain line) to detect buggy code programmatically. I don't know why, but I'm really enthusiastic about improving productivity on software engineering (which you can confirm on my outstanding 1700+ commits dotfiles repository).
- My experience at Cookpad made me realize test-execution time is the most potent problem
I had been working at Cookpad Inc. from May 2014 to January 2015, during which I realized the more significant problem in software engineering lies in test-execution time rather than in bug-detecting time. From then on, I investigated and tried a lot of approaches like nviennot/rspec-console (for local development) and cookpad/rrrspec (for CI).
- This has been the idea of my master thesis
One day, I realized that I can be selective about which test cases to run for a commit if I could know which test cases were influenced by the changes introduced. However, I have been overwhelmed by the variety of testing frameworks and the variety of open source projects I want to use as research subjects. So, I felt this is a good opportunity to focus on Minitest (and RSpec, because I use it) as testing frameworks and Rails (which, by the way, I really love) as a subject for my research.
This project consists of one gem (which we call "pickytest").
- Generate code-to-test mappings for a given commit
- Determine which test cases should be run for a given commit using (1) the code-to-test mappings for a "base" commit (likely to be the merge-base of the given commit and the HEAD of master branch) and (2) VCS diff information between the given commit and the "base" commit.
Both can be run on any CIs. Users will be able to use it by only writing some setup code in, say, spec_helper.rb
file. Running only selected test cases on CIs might be a bit tricky, so I might implement a feature to generate another directory named selected_tests
or selected_specs
which contains files with selected test cases. In that case, users can run all selected test cases easily.
This approach takes the same approach described in this article: Predicting Test Failures | Tenderlovemaking.
The overall idea is to peek in coverage information after each test run and calculate code-to-test mappings. The problem of this approach is that this needs Coverage.peek_result
method, which is not present in current stable releases of Rubies. I noticed Ruby 2.3.0-dev has this method, so this approach forces users to either (1) patch Ruby themselves with the patch which add Coverage.peek_result
method or (2) use Ruby 2.3.0-dev. In my opinion, this is not desirable comparing to the second approach.
The first approach needed Coverage.peek_result
because of these 2 limitations:
- To get coverage, Ruby source files should be required or loaded between
Coverage.start
andCoverage.result
Coverage.result
clears out all the coverage information
In code, the limitations looks like this:
a_method.rb (gist link)
def a_method
s = 0
10.times do |x|
s += x
end
s
end
experiment.rb (gist link)
require 'coverage'
Coverage.start
require './a_method.rb' # => true
a_method
p Coverage.result # => {"/Users/.../a_method.rb"=>[1, 1, 1, 10, nil, 1, nil]}
# Does not produce coverage because `Coverage.result` clears out the coverage
# p Coverage.result # coverage measurement is not enabled (RuntimeError)
# Does not produce coverage because the file `a_method.rb` is not loaded
Coverage.start
a_method
p Coverage.result # => {"/Users/.../a_method.rb"=>[]}
# Does not produce coverage because the file `a_method.rb` is not loaded
Coverage.start
require './a_method.rb' # => false
a_method
p Coverage.result # => {"/Users/.../a_method.rb"=>[]}
# Unload `a_method.rb`
$".delete_if { |s| s.include?('a_method.rb') }
# Does produce coverage because the file `a_method.rb` is loaded
Coverage.start
require './a_method.rb' # => true
a_method
p Coverage.result # => {"/Users/.../a_method.rb"=>[1, 1, 1, 10, nil, 1, nil]}
This means we can generate code-to-test mappings in this procedure:
- start new Ruby process or unload all loaded files
- call
Coverage.start
require
all files- run single test case
- call
Coverage.result
and save code-to-test mappings - loop 1 to 5 for all test cases
- combine all code-to-test mappings into one file
This is expected to be extremely slow. But I think this is a bearable overhead to reduce test execution time later.
For quick experiment, I executed a single test in Rails repository and benchmarked it. The result was like this:
(machine spec)
MacBook Pro (Retina, 13-inch, Late 2013)
Processor 2.8 GHz Intel Core i7
Memory 16 GB 1600 MHz DDR3
(benchmark)
$ n=0; time ( while (( n++ < 10000 )); do ruby -w -Itest test/mail_layout_test.rb -n test_explicit_class_layout; done )
119.15s user 24.78s system 97% cpu 2:27.68 total
119.15s for 100 execution, so it took roughly 1.2s for this one test case to run.
Let's say test preparation (like loading files) costs 1.2 seconds and one test case run costs C seconds on average in Rails repository. Because Rails has about 11000 test cases if I get it right ($ grep -R 'def test_' . | wc -l
resulted in 10758), it will take at least 3.5 hours ((11000 * 1.2).to_f / 60 / 60 = 3.67) for only test preparations. Total time will hugely depend on the constant C, but I believe it will not exceed 24 hours.
- May 25: Project Start
- June 1: Decide which approach to take
- June 8: pickytest prototype (generate code-to-test mappings, select test cases given code-to-test mappings and a commit) is ready
- June 9-15: Try using it in some repositories and improve
- June 16: Beta release
- June 16-30: Gather feedbacks and improve on them
- July 1-14: Plan an experiment which can estimate how effective this approach is
- July 15: Release
- July 15-: Maintenance and data gathering
- August 9: Publish quick analysis of gathered data
Because test execution time on Travis CI is really long! And this approach is expected to cut down the test execution time by quite a significant amount. This will benefit Ruby on Rails because people can quickly know if a pull request breaks something, which makes development faster.
Recently I became able to submit pull requests to open source projects. My enthusiasm lies in Vim, so my contributions are mostly for Vim related projects. I submitted a pull request to vimperator/vimperator-labs and some vim plugins like saihoooooooo/glowshi-ft.vim, takac/vim-hardtime and Shougo/unite.vim.
Because it's open!
Here are big reasons why I love open source:
- I can learn a ton
- by reading source code
- by interacting with other developers around the world
- I can have big dreams
- of creating popular project which can gain 10000+ stars
- of becoming a committer of popular projects
- I can be confident to use external open source libraries
- because I myself can fix it, at least
- I can enjoy writing code!
- emoji, LGTM, etc...
I prospect this project can be released in 8 weeks. I want to conduct an experiment using this, and it will take some more weeks. Of course the maintenance continues forever.
I can start as soon as "Student coding" starts, which means May 25, 2015.
I can use most of my time for this project if I were approved as GSoC participant. I want to say 24/7, but to be realistic, I say I can devote 8 hours a day, 5 days a week.
I am planning to stay in Silicon Valley this summer.
What timezone will you be working in and what hours do you plan to work? (so we can best match mentors)
I will be working in GMT -7:00 timezone. I plan to work from 07:00 to 17:00 (I am a super early bird).
I have a workshop from August 13 to August 27, and I will not be available during the period. Other than that, I have no commitments.
No.
No.
The biggest reason is that I think this is a great opportunity to jump into OSS community. I have sent pull requests to some small projects and I have been dreaming of becoming a committer of big projects. However, participating in communities of those big projects is scary for me because I think my skill is not enough to participate in those big projects. Using GSoC, I can interact with people in OSS community and I might be able to get precious feedbacks, with which I can know what skills I need in order to join OSS community more actively.
So, in short, I want to be confident to join OSS community through GSoC.
- Because I used Ruby on Rails intensively with my part-time job at Cookpad Inc.
- Because I love Ruby on Rails and the community around it (there are many useful gems out there), and I want to participate in that community
- Because the idea of "Improve Rails Testing Ecosystem" matches my area of enthusiasm
I want to participate because I want an opportunity to start committing to Ruby on Rails and other projects around it. Ruby on Rails wants to choose me because I will be a contributor to Ruby on Rails community after GSoC ends. As I noted previously, I will use GSoC to know what I need to learn in order to join OSS community. Because Ruby on Rails is the framework I use the most and I love the most, I want to contribute to it in the future.