← archive

Guard down, Vim and Tmux are here!

August 11, 2013
tmux ruby vim

Do you practice Test Driven Development? If you do, how do you do it?

Well if your answer is "I do it by using Spork with Guard.", then you know that it runs every time you save a file. Same can apply to any other autotesting tool.

Isn't that too often?

What's itching me

I'm a Vim user and I'm used to saving my files frequently, this keybinding makes it super-easy to do so:

"" saving with ctrl+s
map <C-S> :w<CR>
imap <C-S> <Esc>:w<CR>

So let me explain what do I mean by "too often".

Guard watches for filesystem changes, while Spork preforks your Rails environment to speed up the tests. If you set up them properly, which sometimes can be a pretty painful process, your tests will run for each update of the directory being watched. It means that you will spend a lot of time customizing these two to work well together and end up with a watcher that runs your test inside a preforked Rails environment (which still takes time to load and it's still not fast enough for unit tests). How many times did you save your file to immediately notice a typo?

There seems to be a new kid on the block, but I will not cover it this post. I will focus on my current routine.

Current routine

Zsh is great, Tmux is great and Vim is so awesome, using it feels like doing evil things. I use them on a daily basis and they've proven to be a great trio! There are a lot of resources about them written by very smart people and you can find links to some of them on the bottom of the page.

Currently, I'm using Zsh + Tmux + Vim and some plugins to run only the relevant tests with a few key presses.

Here's how it looks in action:

What am I doing here? As you can see, my cursor is positioned inside a Rails model file. I simply hit ,s and specs for this model are being ran in the another Tmux pane. This functionality is achieved with two great Vim plugins - Turbux and vimux.

Turbux is designed to speed up your TDD cycle by using a single key mapping to run the most relevant test based on the current file in Vim, while vimux is a tool for interacting with tmux from Vim. Turbux depends on unavoidable rails.vim to determine the most relevant test and adds some of its own default mappings.

These are the default Turbux mappings:

map <leader>t <Plug>SendTestToTmux
map <leader>T <Plug>SendFocusedTestToTmux

The default mappings clashed with my Command-T mappings, so I had to rebind them to <leader>s.

" disable default turbux mappings because they clash with Command-T
let g:no_turbux_mappings = "true"
map <leader>s <Plug>SendTestToTmux
map <leader>S <Plug>SendFocusedTestToTmux

As you might have guessed, my leader is mapped to comma.

let mapleader=","                                   " map leader to , instead of to slash

Trouble with Zeus

On the first attempt, I run my specs by using Zeus and you can see that zeus is prefixed to rspec command. Although Zeus is meant for preforking and therefore speeding up the runtime of your specs, it's slowing things down in this scenario.

Why? Well, because I'm testing my models without requiring Rails and I have my business logic decoupled into extensions. That's why I have all that include lines in my model.

While Zeus is slowing things down here, it certainly speeds up things in all other kinds of tests. I want to be able to turn it off and on inside Vim.

Helpfile for Turbux suggests this:

Use the following in your vimrc to set a common command prefix for prepending
all commands:
>
          let g:turbux_command_prefix = 'bundle exec' " default: (empty)
<

So I could set my g:turbux_command_prefix to zeus, but that means I would use Zeus all the time. I need something different, like a toggle function for this. It's easy to write if you know a little bit of Vimscript:

" I mostly use zeus to run tests
" I don't use it all the time though
" this function enables toggling when using turbux
nnoremap <leader>z :call ToggleZeus()<cr>
function! ToggleZeus()
  if g:turbux_command_prefix == 'zeus'
    echo 'zeus disabled'
    let g:turbux_command_prefix = ''
  else
    echo 'zeus enabled'
    let g:turbux_command_prefix = 'zeus'
  endif
endfunction

That's it! I can now toggle to run my specs with or without Zeus. :)

Focused tests

In the end, I just want to show how you can run focused test with Turbux.

Resources

There are a lot of additional resources on the web and I would definitely recommend:

Want to talk more about this or any other topic? Email me. I welcome every email.