py-test-runner.vim


Ⅰ. 插件描述

Run (Python) unit tests under cursor

Ⅱ. 基本信息

创建日期:  2019-04-04
使用用户:  1
Github星:  1
插件作者:  Marius Gedminas

Ⅲ. 安装方法

使用Vundle管理器安装

在你的.vimrc下添加:
Plugin 'mgedmin/py-test-runner-vim'
… 然后在Vim中运行以下命令:
:source %
:PluginInstall

对于Vundle版本 < 0.10.2,请用上面的Bundle替换Plugin。

使用NeoBundle管理器安装

在你的.vimrc下添加:
NeoBundle 'mgedmin/py-test-runner-vim'
… 然后在Vim中运行以下命令:
:source %
:NeoBundleInstall

使用VimPlug管理器安装

在你的.vimrc下添加:
Plug 'mgedmin/py-test-runner-vim'
… 然后在Vim中运行以下命令:
:source %
:PlugInstall

使用Pathogen管理器安装

在终端中运行以下命令:
cd ~/.vim/bundle
git clone https://github.com/mgedmin/py-test-runner.vim

Ⅳ. 文档说明

Overview

Vim script to run the tests for the current file/class/function.

Supports various Python test runners including

  • pytest
  • nose
  • zope.testrunner
  • django test

Demo:

.. image:: screencast.gif
:alt: asciicast
:width: 590
:height: 396
:align: center
:target: https://asciinema.org/a/238972

.. contents::

Installation

I recommend vim-plug_::

Plug 'mgedmin/taghelper.vim'
Plug 'mgedmin/py-test-runner.vim'

You'll also need taghelper.vim_ (or the older pythonhelper.vim_), and I
recommend asyncrun.vim_ too.

Needs Vim built with Python support.

Usage

The plugin defines the following commands:

:RunTestUnderCursor

Runs a single test function/method/class/module, depending on where your
cursor is.  Can run the test asynchronously if you have asyncrun.vim_
installed and have defined the ``:Make`` command `as documented in the wiki
<https://github.com/skywind3000/asyncrun.vim/wiki/Replace-old-make-command-with-AsyncRun>`__.

:RunTest name-of-test

Runs a single test function/method/class/module.

:RunLastTestAgain

Repeats the last test run.

:CopyTestUnderCursor

Copies the command to run a single test function/method/class/module into
the system clipboard, so you can paste it into a terminal window and not
block your Vim instance.

Keyboard shortcuts

If you want some, copy and paste this into your .vimrc::

map <C-F9> :RunTestUnderCursor<CR>
map <C-S-F9> :RunLastTestAgain<CR>

Status line

If you're running the tests asynchronously it can be helpful to indicate the
test status (running/pass/fail) by changing the status line color.

You can define the higlight groups like ::

hi StatusLineNeutral
            \ term=bold,reverse cterm=bold,reverse gui=bold,reverse
hi StatusLineRunning ctermfg=53 guifg=#5f005f
            \ term=bold,reverse cterm=bold,reverse gui=bold,reverse
hi StatusLineSuccess ctermfg=22 guifg=#005f00
            \ term=bold,reverse cterm=bold,reverse gui=bold,reverse
hi StatusLineFailure ctermfg=52 guifg=#5f0000
            \ term=bold,reverse cterm=bold,reverse gui=bold,reverse
hi! link StatusLine StatusLineNeutral

and then :RunTestUnderCursor will detect this and link StatusLine to
StatusLineRunning when the test process starts. It's up to you to define
an asyncrun exit callback to link it to success/failure as appropriate::

fun! OnAsyncRunExit()
  if g:asyncrun_status == 'success'
    hi! link StatusLine StatusLineSuccess
  elseif g:asyncrun_status == 'failure'
    hi! link StatusLine StatusLineFailure
  endif
  redrawstatus!
endf
let g:asyncrun_exit = "call OnAsyncRunExit()"

I'm considering removing the half-finished integration and suggesting you do
the initial linking via ::

augroup AsyncRun
  au!
  au User AsyncRunStart hi! link StatusLine StatusLineRunning | redrawstatus!
augroup END

Configuration file

This plugin reads ~/.vim/py-test-runner.cfg if it exists. It should be an INI
file like this::

[default]
runner = pytest

[runner:mytestrunner]
command = mytestrunner
filter_for_file = {filename}
filter_for_function = {filename}::{function}
filter_for_class = {filename}::{class}
filter_for_method = {filename}::{class}::{method}
filter_for_doctest = -k {function}

[path:~/src/myproject]
runner = mytestrunner
command = venv/bin/mytestrunner

[default] section


The ``[default]`` section has the following settings:


**runner**

    Specifies the default test runner.  If omitted, the default is ``pytest``.
    You can use any of the predefined test runners (``pytest``, ``nose``,
    ``zope``, and ``django``), or any custom test runner if you have a
    corresponding ``[runner:foo]`` section.

    This setting can be overridden by ``[path:...]`` sections and manually,
    if you ``:call pytestrunner#use(runner)`` or set ``g:pyTestRunner``.


**ignore_functions_and_methods**

    Specifies a whitespace-separated list of function/method names that
    should not be considered to be tests.

    For example, this is the default ignore list::

        [default]
        ignore_functions_and_methods =
            __init__
            setUp
            tearDown
            test_suite

    When the cursor is inside a function/method with one of these names,
    it will be ignored (and the scope of the test will be the entire
    module/class).

    This setting can be overridden by ``[runner:...]`` sections, and by
    ``[path:...]`` sections.


[runner:...] sections

The [runner:NAME] sections define/override test runners and have the
following settings:

command

Specifies the main test runner command.  This can contain arguments.
No shell escaping is done, so be careful!

Examples::

    [runner:pytest]
    command = pytest -ra

    [runner:tox]
    command = tox -e py27,py37 --

This setting can be overridden by ``[path:...]`` sections and manually, by
calling ``pytestrunner#use(runner, command)`` or by setting
``g:pyTestRunnerCommand``.

The full command is constructed from ``command`` and the multiple
``filter_for_...`` settings in the following order:

#. command
#. filter_for_file, if not blank
#. filter_for_directory, if not blank
#. filter_for_package, if not blank
#. filter_for_module, if not blank
#. one of filter_for_function, filter_for_doctest, filter_for_class,
   filter_for_method, whichever is applicable

As a special case, if filter_for_function (or filter_for_doctest, or
filter_for_class, or filter_for_method, whichever was picked) mentions the
``{filename}`` placeholder, filter_for_file, filter_for_directory,
filter_for_package and filter_for_module will be skipped.

filter_for_file

Specifies how to tell the test runner which test file is interesting.

Example::

    [runner:pytest]
    filter_for_file = {filename}

Whether the ``{filename}`` placeholder is replaced with a relative or
absolute filename depends on the ``absolute_filenames`` setting.

You will want to specify either ``filter_for_file`` or
``filter_for_module``, but not both.  (I don't know what will happen
if you specify both.)

This setting can be overridden by ``[path:...]`` sections.

filter_for_directory

Specifies how to tell the test runner which test directory is interesting.

Example::

    [runner:...]
    filter_for_directory = {directory}

Whether the ``{directory}`` placeholder is replaced with a relative or
absolute filename depends on the ``absolute_filenames`` setting.

You will want to specify either ``filter_for_directory`` or
``filter_for_filename``, but not both.  (I don't know what will happen
if you specify both.)

You will want to specify either ``filter_for_directory`` or
``filter_for_package``, but not both.  (I don't know what will happen
if you specify both.)

This setting can be overridden by ``[path:...]`` sections.

filter_for_package

Specifies how to tell the test runner which test package is interesting.

Example::

    [runner:zope]
    filter_for_package = -s {package}

The logic that computes Python package names from directory names
relies on the presence/absence of ``__init__.py`` files and breaks if
you use PEP-420 namespace packages.

You will want to specify either ``filter_for_package`` or
``filter_for_filename``, but not both.  (I don't know what will happen
if you specify both.)

You will want to specify either ``filter_for_package`` or
``filter_for_directory``, but not both.  (I don't know what will happen
if you specify both.)

This setting can be overridden by ``[path:...]`` sections.

filter_for_module

Specifies how to tell the test runner which test module is interesting.

Example::

    [runner:zope]
    filter_for_module = -m {module}

The module name is just the filename without the ``.py`` extension.

You will want to specify either ``filter_for_module`` or
``filter_for_filename``, but not both.  (I don't know what will happen
if you specify both.)

This setting can be overridden by ``[path:...]`` sections.

filter_for_function

Specifies how to tell the test runner which test function is interesting.

Filtering by test function requires pythonhelper.vim_ to be installed.

Examples::

    [runner:zope]
    filter_for_function = -t {function}

    [runner:pytest]
    filter_for_function = {filename}::{function}

This setting can be overridden by ``[path:...]`` sections.

filter_for_doctest

Specifies how to tell the test runner which doctest function is
interesting.

Filtering by test function requires pythonhelper.vim_ to be installed.

Regular functions from doctest functions are distinguished by name
(functions starting with ``test`` are assumed to be regular functions).

Examples::

    [runner:zope]
    filter_for_doctest = -t {function}

    [runner:pytest]
    filter_for_doctest = -k {function}

If this setting is not specified, ``filter_for_function`` is used
instead for doctest functions as well.

This setting can be overridden by ``[path:...]`` sections.

filter_for_class

Specifies how to tell the test runner which test class is interesting.

Filtering by test class requires pythonhelper.vim_ to be installed.

Examples::

    [runner:zope]
    filter_for_class = -t {class}

    [runner:pytest]
    filter_for_class = {filename}::{class}

If this setting is not specified, ``filter_for_function`` is used
instead.

This setting can be overridden by ``[path:...]`` sections.

filter_for_method

Specifies how to tell the test runner which test method is interesting.

Filtering by test method requires pythonhelper.vim_ to be installed.

Examples::

    [runner:zope]
    filter_for_method = -t '{method} \(.*\.{class}\)'

    [runner:pytest]
    filter_for_class = {filename}::{class}::{method}

    [runner:nose]
    filter_for_class = {filename}::{class}.{method}

If this setting is not specified, ``filter_for_function`` is used
instead and gets the method name (discarding the class name).

This setting can be overridden by ``[path:...]`` sections.

absolute_filenames

Set to a true value (``true``, ``yes``, ``1``) if you want ``{filename}``
and ``{directory}`` placeholders to be absolute.

This is helpful when the test runner script changes its working directory
before it starts looking for files.

Set to a false value (``false``, ``no``, ``0``) if you want ``{filename}``
and ``{directory}`` placeholders to be exactly as they appear in Vim
(so they could be absolute or relative, depending on how you opened
the file).

Defauls to false.  Can be overridden by ``[path:...]`` sections.

clipboard_extras

Extra command-line flags to be added when using :CopyTestUnderCursor.

Use this to add colors or progress bars that would otherwise confuse Vim's
:make.

These flags are added to the beginning of the command line.

Example::

    [runner:zope]
    clipboard_extras = -pvc

This setting can be overridden by ``[path:...]`` sections.

clipboard_extras_suffix

Extra command-line flags to be added when using :CopyTestUnderCursor.

Use this to add colors or progress bars that would otherwise confuse Vim's
:make.

These flags are added to the end of the command line.

No shell escaping is done so you can in fact do something like ::

    [runner:zope]
    clipboard_extras = 2>&1 | less -R

to pipe the test runner's output to a pager.

This setting can be overridden by ``[path:...]`` sections.

[path:...] sections


The ``[path:PATH]`` sections define overrides for your projects
identified by path names and have the following settings:

**runner**

    Overrides the ``runner`` from the ``[defaults]`` section.

    Example::

        [path:~/src/vim-plugins/py-test-checker.vim]
        command = coverage run -m pytest

    Can be overridden by setting ``g:pyTestRunner`` or calling
    ``pytestrunner#use(runner)``.

**command**

    Overrides the ``command`` from the ``[runner:...]`` section.

    Example::

        [path:~/src/vim-plugins/py-test-checker.vim]
        command = coverage run -m pytest

    Can be overridden by setting ``g:pyTestRunnerCommand`` or calling
    ``pytestrunner#use(runner, command)``.


**filter_for_file**,
**filter_for_directory**,
**filter_for_package**,
**filter_for_module**,
**filter_for_function**,
**filter_for_doctest**,
**filter_for_class**,
**filter_for_method**

    Override the corresponding setting from the ``[runner:...]`` section.

    You're not expected to ever need this.

**absolute_filenames**,
**clipboard_extras**,
**clipboard_extras_suffix**

    Override the corresponding setting from the ``[runner:...]`` section.

    These look like settings it can make sense to override on a
    per-project basis.  Maybe.


Global variables
----------------

The following global variables are used:

**g:pyVimRunCommand** (default: "")

    Vim command to run an external process (after setting ``&makeprg``).
    If blank, the plugin will use ``:Make`` if such a user-defined
    command exists, otherwise it will use ``:make``.

    asyncrun.vim_ recommends defining ::

      command! -bang -nargs=* -complete=file Make AsyncRun -program=make @ <args>

    so you can run commands in the background

**g:pyTestRunner** (default: "")

    Test runner to use.  If not blank, overrides the ``runner`` setting in the
    configuration file.

    The ``:call pytestrunner#use(...)`` convenience command writes to
    this variable.

**g:pyTestRunnerCommand** (default: "")

    Test runner command to use.  If not blank, overrides the ``command``
    setting in the configuration file.

    The ``:call pytestrunner#use(...)`` convenience command writes to
    this variable.

**g:pyTestLastTest** (default: "")

    This is not a configuration setting, but instead the filter describing
    the last test executed via :RunTestUnderCursor.  It is used by
    :RunLastTestAgain.



Backwards compatibility
-----------------------

There are several functions that streamline the setup for the most common test
runners, left for backwards compatibility:


**:call UsePyTestTestRunner("pytest -ra")**

    Use pytest, which uses commands like ::

        pytest -ra <filename>::<class>::<method>

    You can optionally specify the main executable, which is helpful if you use
    multiple virtualenvs, e.g. ::

        :call UsePyTestTestRunner("tox -e py27,py37 --")

    assuming your tox.ini has ::

        [testenv]
        commands = pytest {posargs}

    ``:call UsePyTestTestRunner(...)`` is exactly equivalent to
    ``:call pytestrunner#use("pytest", ...)`` and is provided for
    backwards compatibility.


**:call UseZopeTestRunner("bin/test")**

    Use the Zope test runner, which uses commands like ::

        bin/test -s <package> -m <module> -t '<method> (class <Class>)'

    You can optionally specify the main executable or pass additional arguments,
    e.g. ::

        :call UseZopeTestRunner("venv/bin/zope-testrunner -vv")

    ``:call UseZopeTestRunner(...)`` is exactly equivalent to
    ``:call pytestrunner#use("zope", ...)`` and is provided for
    backwards compatibility.


**:call UseNoseTestRunner("nosetests")**

    Use the nose test runner, which uses commands like ::

        nosetests <filename>:<class>.<method>

    ``:call UseNoseTestRunner(...)`` is exactly equivalent to
    ``:call pytestrunner#use("nose", ...)`` and is provided for
    backwards compatibility.


**:call UseDjangoTestRunner("bin/django test")**

    Use the Django test runner.  Assumes you're using django-nose, which uses
    commands like ::

        bin/django test <filename>:<class>.<method>

    You can optionally specify the main executable or pass additional arguments,
    e.g. ::

        :call UseDjangoTestRunner("python manage.py test")
        :call UseDjangoTestRunner("venv/bin/django-admin test")

    ``:call UseDjangoTestRunner(...)`` is exactly equivalent to
    ``:call pytestrunner#use("django", ...)`` and is provided for
    backwards compatibility.


Backwards incompatibiliy
------------------------

The following global variables are **no longer used**:


**g:pyTestRunner**

    This used to define the test runner command, instead of selecting the
    test runner configuration section.  If you keep defining it, you will
    get errors.

    Use **g:pyTestRunnerCommand** instead.


**g:pyTestRunnerTestFiltering**

    This is now completely ignored.

    Define a ``[runner:...]`` or ``[path:...]`` section with ::

        filter_for_function = -t {function}

    instead.


**g:pyTestRunnerDoctestFiltering**

    This is now completely ignored.

    Define a ``[runner:...]`` or ``[path:...]`` section with ::

        filter_for_doctest = -t {function}

    instead.

**g:pyTestRunnerTestFilteringClassAndMethodFormat**

    This is now completely ignored.

    Define a ``[runner:...]`` or ``[path:...]`` section with ::

        filter_for_method = -t {class}.{method}

    instead.


**g:pyTestRunnerTestFilteringBlacklist**

    This is now completely ignored.

    Define a ``[default]`` or ``[runner:...]`` or ``[path:...]`` section with ::

        ignore_functions_and_methods =
            __init__
            setUp
            tearDown
            test_suite

    instead.


**g:pyTestRunnerDirectoryFiltering**

    This is now completely ignored.

    Define a ``[runner:...]`` or ``[path:...]`` section with ::

        filter_for_directory = -s {directory}

    instead.

**g:pyTestRunnerFilenameFiltering**

    This is now completely ignored.

    Define a ``[runner:...]`` or ``[path:...]`` section with ::

        filter_for_file = {filename}

    instead.


**g:pyTestRunnerUseAbsoluteFilenames**

    This is now completely ignored.

    Define a ``[runner:...]`` or ``[path:...]`` section with ::

        absolute_filenames = yes

    instead.


**g:pyTestRunnerPackageFiltering**

    This is now completely ignored.

    Define a ``[runner:...]`` or ``[path:...]`` section with ::

        filter_for_package = -s {package}

    instead.


**g:pyTestRunnerModuleFiltering**

    This is now completely ignored.

    Define a ``[runner:...]`` or ``[path:...]`` section with ::

        filter_for_module = -m {module}

    instead.


**g:pyTestRunnerClipboardExtras**

    This is now completely ignored.

    Define a ``[runner:...]`` or ``[path:...]`` section with ::

        clipboard_extras = -pvc

    instead.


**g:pyTestRunnerClipboardExtrasSuffix**

    This is now completely ignored.

    Define a ``[runner:...]`` or ``[path:...]`` section with ::

        clipboard_extras_suffix = 2>&1 | less -R

    instead.


Bugs
----

- Test coverage is incomplete

- [path:...] runner=... probably overrides g:pyTestRunner, contradicting
  the documentation

- there's no error if you specify an empty command in a config file
  (or set g:pyTestRunnerCommand to a bunch of spaces)

- there's no error if a [path:...] section specifies a bad runner


Copyright
---------

``test-runner.vim`` was written by Marius Gedminas <marius@gedmin.as>.
Licence: MIT.


.. _vim-plug: https://github.com/junegunn/vim-plug
.. _asyncrun.vim: https://github.com/skywind3000/asyncrun.vim
.. _pythonhelper.vim: https://github.com/mgedmin/pythonhelper.vim

添加新评论