As most people I am annoyed with repeating stuff over and over. And today my workflow about switching between test files pissed me off. So I wrote two little functions that switches between unit tests and their corresponding SUTs. It also creates them if non-existent.
Function one: self-contained Symfony bundles
If you prefer to write self-contained bundles that also contain their tests, following will work.
Directory structure
projectroot/
- src/Your/Bundle/Service/
- src/Your/Bundle/Tests/Service
Vim function
nnoremap <leader>ta :call SymfonySwitchToAlternateFile()<cr>
nnoremap <leader>tsa <c-w>v:call SymfonySwitchToAlternateFile()<cr>
" changes to test/sut files
" following structure:
" sut: src/Acme/Bundle/Service/MyService.php
" test: src/Acme/Bundle/Tests/Service/MyServiceTest.php
function! SymfonySwitchToAlternateFile()
let l:f = expand('%')
let l:preceedingDirsToKeep = 2
let l:is_test = expand('%:t') =~ "Test\."
if l:is_test
" remove phpunit_testroot
let l:f = substitute(l:f, 'Tests/','','')
" remove 'Test.' from filename
let l:f = substitute(l:f,'Test\.','.','')
else
let l:pathParts = split(expand('%:r'), '/')
let l:startingPath = l:pathParts[0:l:preceedingDirsToKeep]
let l:endPath = l:pathParts[(l:preceedingDirsToKeep+1):]
let l:combinedPath = l:startingPath + ['Tests'] + l:endPath
let l:f = join(l:combinedPath, '/') . 'Test.php'
if !filereadable(l:f)
let l:new_dir = substitute(l:f, '/\w\+\.php', '', '')
exe ":!mkdir -p ".l:new_dir
endif
endif
" is there already a window the wanted file?
let win = bufwinnr(l:f)
if l:win > 0
execute l:win . "wincmd w"
else
execute ":e " . l:f
endif
endfunction
Function two: identifier in project root
I’m currently working on a Symfony project that uses Codeception for its testing. Codeception puts all tests into a tests/<testtype>
directory in your project root. <testtype>
might be unit, functional or acceptance, i.e. ‘tests/unit/..’.
Directory structure
projectroot/
- src/Your/Bundle/...
- tests/unit/src/Your/Bundle/...
- tests/functional/src/Your/Bundle/...
- tests/acceptance/src/Your/Bundle/...
Vim function
nmap <leader>tu :call SwitchBetweenFiles('php', 'tests/unit/', 'src/', 'Test')<cr>
nmap <leader>tsu <c-w>v:call SwitchBetweenFiles('php', 'tests/unit/', 'src/', 'Test')<cr>
nmap <leader>tf :call SwitchBetweenFiles('php', 'tests/functional/', 'src/', 'Test')<cr>
nmap <leader>ta :call SwitchBetweenFiles('php', 'tests/acceptance/', 'src/', 'Test')<cr>
" Parameters:
"
" fileExtension: the file extension this script should act on, i.e. 'php'
" (without dot)
"
" firstDirBeginning: a file path that identifies the first type
" of paths, i.e. 'tests/unit/'
"
" secondDirBeginning: a file path pattern that identifies the second type
" of paths, i.e. 'src/'
"
" filenameAddition: string that should be removed from the first filename and
" added to the second. Should be for example 'Test' if your testfile filename has the suffix
" 'Test' as in /path/MyServiceTest.php
function! SwitchBetweenFiles(fileExtension, firstDirBeginning, secondDirBeginning, filenameAddition)
let f = bufname("%")
if f =~ '.'.a:fileExtension
if f =~ '\<'.a:firstDirBeginning && f =~ a:filenameAddition.'\.'.a:fileExtension
let filename = substitute(substitute(f, a:firstDirBeginning, '', ''), a:filenameAddition, '', '')
if !filereadable(filename)
let new_dir = substitute(filename, '/\w\+\.'.a:fileExtension, '', '')
exe ":!mkdir -p ".new_dir
endif
exe ":e ".filename
elseif f =~ '\<'.a:secondDirBeginning && f !~ a:filenameAddition.'\.'.a:fileExtension
let filename = substitute(substitute(f, a:secondDirBeginning, a:firstDirBeginning.a:secondDirBeginning, ''), '.'.a:fileExtension, a:filenameAddition.'.'.a:fileExtension, '')
if !filereadable(filename)
let new_dir = substitute(filename, '/\w\+'.a:filenameAddition.'\.'.a:fileExtension, '', '')
exe ":!mkdir -p ".new_dir
endif
exe ":e ".filename
else
echom "Could not switch because needed patterns not matched."
endif
endif
endfunction
I hope you’ll profit from it.