I finally cleansed my spirit and started writing tests before code. I am
hardly the New Year resolution kind of character, but I'd been meaning to
do it ever since I heard about this funny methodology. I had written tests
before, of course, but never systematically and I had only thought of them
explicitly as being part of design when I encountered things that were
difficult to test bacause they weren't designed with testing
in mind. If you've ever read anything about test driven development
(or Extreme Programming, which seems to feature TDD quite prominently),
and certainly if you've been doing it, you'll know what I'm talking about.
I'm very, very new and don't pretend to be an expert about these
things. So I'm only here for two modest contributions:
First, to encourage you to do TDD if you aren't doing it yet. It's
not that hard and it's immediately rewarding.
Second, I was looking for some tips about doing it with vim and only
found scattered pieces here and there. I hacked together something a
little bit better than what I found so far, and am posting it here with
the hope that you can use it and comment with improvements.
Setup
First of all, some organizational recommendations.
- Put your tests in t/ and follow the convention of
##-name.t.
Dot-t helps prove run only your tests and nothing
else. Number your tests in the order that makes sense to usually test,
but avoid hard interdependencies among tests and occasionally run
prove --shuffle.
- Start up vim in the base directory of the project.
Run ctags -R here. If
you use sessions, save them them here too. (Add the tags
and session files to your MANIFEST.SKIP or equivalent, if you're
packaging.)
- At the top of your .t files, put this line that gives you syntax highlighting.
# vim: ts=4 sw=4 syn=perl :
You can put in other options, of course, but if they're global
to your perl preferences then .vimrc would be a better place. Alternatively,
you can say au BufRead,BufNewFile *.t setfiletype=perl
in ~/.vim/ftdetect/perl_test.vim — credit Ben Prew.
Using it
The idea here is that most of the time you are working from on
a particular test, and when you fix something you saw broken there,
that's usually the first test you want to try again after you make your
fix. So we have a notion of a "current testfile" that should be easy to
set (and unset), and which should be trivial to run. If you rush off
to fix a bug somewhere, you don't want to lose the current test. If a
test fails, you want to jump to the compilation error if there was one,
or to the definition of the failed test if there wan't. If you aren't
familiar with vim's quickfix
feature, read about it now.
So it's simple really. Have vim load the file
below* and then you just need to know
three keybindings. They all work in command mode. As a bonus, if
you ,w on a code file and not on a test, a subsequent
,t will run it against perl -c to check for
compilation errors.
" perltest.vim - test driven development for Perl with vim
"
" ,t -- Run tests
" ,w -- Set current file as test file. Only this test will run.
" ,W -- Unset current test file. All tests will run.
"
" v1.02 - Updates at http://perlmonks.org/index.pl?node_id=434793
function! Prove ( taint )
if ! exists("g:testfile")
let g:testfile = "t/"
endif
if g:testfile == "t/" || g:testfile =~ "\.t$"
echo system("prove -lv " . a:taint . g:testfile . " 2>&1 |
+tee " . &errorfile)
else
echo system("perl -c -Ilib " . a:taint . g:testfile . " 2>&1 |
+tee " . &errorfile)
endif
cfile
endfunction
nmap ,t :call Prove ("")<cr>
nmap ,T :call Prove ("-T ")<cr>
nmap ,w :let g:testfile = expand("%")<cr>:echo "testfile is now" g:t
+estfile<cr>
nmap ,W :unlet g:testfile<cr>:echo "testfile undefined; will run all t
+ests"<cr>
" based on compiler/perl.vim by Christian J. Robinson <infynity@onewes
+t.net>
" added formats for test failures
set errorformat=
\%-G%.%#had\ compilation\ errors.,
\%-G%.%#syntax\ OK,
\%+Anot\ ok\%.%#-\ %m,
\%C%.%#\(%f\ at\ line\ %l\),
\%m\ at\ %f\ line\ %l.,
\%+A%.%#\ at\ %f\ line\ %l\\,%.%#,
\%+C%.%#
" FIXME make this more local. Needed for redirection syntax which isn'
+t csh compatible
set sh=/bin/sh
" Just more convenient when shelling out a lot.
set autowrite
* TODO
I'll update the above with your suggestions, starting with fixing the
following issues:
- Where to install this / how to have this loaded automatically? This should be loaded automatically when editing files with names matching
\.(pl|m)|t$. Anyone remember how to do that?
For now, I put this in ~/perltest.vim and do :so ~/perltest.vim
- Make it local.
Currently this overwrites errorformat, which is kinda
lame if you're also doing development in another language. If the effect
can be localized to this file mode, all the better.
- ...?
See also
ChangeLog
- 2005-03-01T19:48Z - Added lib and taint (Thanks dragonchild). v1.02.
Re: Test driven development with Perl and vim
by dbwiz (Curate) on Feb 26, 2005 at 17:45 UTC
|
| [reply] |
Re: Test driven development with Perl and vim
by leriksen (Curate) on Feb 27, 2005 at 11:19 UTC
|
Nice work - and welcome to the TDD club !!
And for our x?emacs friends, to bind the .t extension to the cperl mode, you can do this
(setq auto-mode-alist (append '(("\\.t$" . cperl-mode)) auto-mode-alis
+t))
...it is better to be approximately right than precisely wrong. - Warren Buffet
| [reply] [d/l] |
Re: Test driven development with Perl and vim
by dragonchild (Archbishop) on Feb 28, 2005 at 19:25 UTC
|
In your .exrc file, add the following lines:
autocmd BufNewFile,BufRead *.p? compiler perl
autocmd BufNewFile,BufRead *.p? map v :make^M
autocmd BufNewFile,BufRead *.p? so ~/perltest.vim
autocmd BufNewFile,BufRead *.t compiler perl
autocmd BufNewFile,BufRead *.t map v :make^M
autocmd BufNewFile,BufRead *.t so ~/perltest.vim
Being right, does not endow the right to be rude; politeness costs nothing. Being unknowing, is not the same as being stupid. Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence. Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.
| [reply] [d/l] |
|
| [reply] [d/l] [select] |
|
autocmd BufNewFile,BufRead *.p? so ~/.vim/perltest.vim
autocmd BufEnter *.p? colors peachpuff
autocmd BufNewFile,BufRead *.t so ~/.vim/perltest.vim
autocmd BufEnter *.t colors blue
And, I make a few changes to my perltest.vim
The main changes are:
- Addition of ,T allowing for make test TEST_VERBOSE=1
- Addition of ,v allowing for compile of .t files. This entailed creating Compile()
- Addition of -l flag to prove, keeping the vim editor in the same directory as the tags file.
I'm still figuring out the various parameters. Heck, I've learned more about the vim settings in the last hour than I had in the 10+ years I've been using vi-based editors! :-)
Being right, does not endow the right to be rude; politeness costs nothing. Being unknowing, is not the same as being stupid. Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence. Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.
| [reply] [d/l] [select] |
|
|
|
Re: Test driven development with Perl and vim
by dragonchild (Archbishop) on Mar 02, 2005 at 14:14 UTC
|
Some more hacking around gives me this. The important change is no more dependency on errors.err. Instead, we use vim's own shell-out buffers, which are better. Plus, the old perl -wc wasn't working for me. And, this is also faster than using system() and gives immediate results, which is nice when you're waiting for 20+ testfiles to run. :-)
function! Prove ( verbose, taint )
if ! exists("g:testfile")
let g:testfile = "t/*.t"
endif
if g:testfile == "t/*.t" || g:testfile =~ "\.t$"
let s:params = "l"
if a:verbose
let s:params = s:params . "v"
endif
if a:taint
let s:params = s:params . "Tt"
endif
execute "!prove -" . s:params . " " . g:testfile
else
call Compile ()
endif
endfunction
function! Compile ()
if ! exists("g:compilefile")
let g:compilefile = expand("%")
endif
execute "!perl -wc -Ilib " . g:compilefile
endfunction
nmap ,t :call Prove (0,0)<cr>
nmap ,tt :call Prove (0,1)<cr>
nmap ,T :call Prove (1,0)<cr>
nmap ,TT :call Prove (1,1)<cr>
nmap ,v :call Compile ()<cr>
Being right, does not endow the right to be rude; politeness costs nothing. Being unknowing, is not the same as being stupid. Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence. Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.
| [reply] [d/l] |
|
|