一个更复杂的设置
我的书——“写地道的Python”,实际上写的是一系列的Python模块和代码。这样做是为了确保所有的示例代码按预期工作。作为我的构建过程的一部分,我运行tox来确保任何新的语法代码能正常运行。我偶尔也看看我的测试覆盖率,以确保没有语法在测试中被无意跳过。因此,我的tox.ini比上面的复杂一些,一起来看一看:
[tox]
envlist=py27, py34
[testenv]
deps=
pytest
coverage
pytest-cov
setenv=
PYTHONWARNINGS=all
[pytest]
adopts=--doctest-modules
python_files=*.py
python_functions=test_
norecursedirs=.tox .git
[testenv:py27]
commands=
py.test --doctest-module
[testenv:py34]
commands=
py.test --doctest-module
[testenv:py27verbose]
basepython=python
commands=
py.test --doctest-module --cov=. --cov-report term
[testenv:py34verbose]
basepython=python3.4
commands=
py.test --doctest-module --cov=. --cov-report term
这个配置文件依旧比较简单。而结果呢?
(idiom)~/c/g/idiom git:master >>> tox
GLOB sdist-make: /home/jeff/code/github_code/idiom/setup.py
py27 inst-nodeps: /home/jeff/code/github_code/idiom/.tox/dist/Writing Idiomatic Python-1.0.zip
py27 runtests: commands[0] | py.test --doctest-module
/home/jeff/code/github_code/idiom/.tox/py27/lib/python2.7/site-packages/_pytest/assertion/oldinterpret.py:3: DeprecationWarning: The compiler package is deprecated and removed in Python 3.x.
from compiler import parse, ast, pycodegen
=============================================================== test session starts ================================================================
platform linux2 -- Python 2.7.5 -- pytest-2.3.5
plugins: cov
collected 150 items
...
============================================================ 150 passed in 0.44 seconds ============================================================
py33 inst-nodeps: /home/jeff/code/github_code/idiom/.tox/dist/Writing Idiomatic Python-1.0.zip
py33 runtests: commands[0] | py.test --doctest-module
=============================================================== test session starts ================================================================
platform linux -- Python 3.3.2 -- pytest-2.3.5
plugins: cov
collected 150 items
...
============================================================ 150 passed in 0.62 seconds ============================================================
_____________________________________________________________________ summary ______________________________________________________________________
py27: commands succeeded
py33: commands succeeded
congratulations :)
(我从输出列表里截取了一部分)。如果想看我的测试对一个环境的覆盖率,只需运行:
$ tox -e py33verbose
-------------------------------------------------- coverage: platform linux, python 3.3.2-final-0 --------------------------------------------------
Name Stmts Miss Cover
------------------------------------------------------------------------------------------------------------------
control_structures_and_functions/a_if_statement/if_statement_multiple_lines 11 0 100%
control_structures_and_functions/a_if_statement/if_statement_repeating_variable_name 10 0 100%
control_structures_and_functions/a_if_statement/make_use_of_pythons_truthiness 20 3 85%
control_structures_and_functions/b_for_loop/enumerate 10 0 100%
control_structures_and_functions/b_for_loop/in_statement 10 0 100%
control_structures_and_functions/b_for_loop/use_else_to_determine_when_break_not_hit 31 0 100%
control_structures_and_functions/functions/2only/2only_use_print_as_function 4 0 100%
control_structures_and_functions/functions/avoid_list_dict_as_default_value 22 0 100%
control_structures_and_functions/functions/use_args_and_kwargs_to_accept_arbitrary_arguments 39 31 21%
control_structures_and_functions/zexceptions/aaa_dont_fear_exceptions 0 0 100%
control_structures_and_functions/zexceptions/aab_eafp 22 2 91%
control_structures_and_functions/zexceptions/avoid_swallowing_exceptions 17 12 29%
general_advice/dont_reinvent_the_wheel/pypi 0 0 100%
general_advice/dont_reinvent_the_wheel/standard_library 0 0 100%
general_advice/modules_of_note/itertools 0 0 100%
general_advice/modules_of_note/working_with_file_paths 39 1 97%
general_advice/testing/choose_a_testing_tool 0 0 100%
general_advice/testing/separate_tests_from_code 0 0 100%
general_advice/testing/unit_test_your_code 1 0 100%
organizing_your_code/aa_formatting/constants 16 0 100%
organizing_your_code/aa_formatting/formatting 0 0 100%
organizing_your_code/aa_formatting/multiple_statements_single_line 17 0 100%
organizing_your_code/documentation/follow_pep257 6 2 67%
organizing_your_code/documentation/use_inline_documentation_sparingly 13 1 92%
organizing_your_code/documentation/what_not_how 24 0 100%
organizing_your_code/imports/arrange_imports_in_a_standard_order 4 0 100%
organizing_your_code/imports/avoid_relative_imports 4 0 100%
organizing_your_code/imports/do_not_import_from_asterisk 4 0 100%
organizing_your_code/modules_and_packages/use_modules_where_other_languages_use_object 0 0 100%
organizing_your_code/scripts/if_name 22 0 100%
organizing_your_code/scripts/return_with_sys_exit 32 2 94%
working_with_data/aa_variables/temporary_variables 12 0 100%
working_with_data/ab_strings/chain_string_functions 10 0 100%
working_with_data/ab_strings/string_join 10 0 100%
working_with_data/ab_strings/use_format_function 18 0 100%
working_with_data/b_lists/2only/2only_prefer_xrange_to_range 14 14 0%
working_with_data/b_lists/3only/3only_unpacking_rest 16 0 100%
working_with_data/b_lists/list_comprehensions 13 0 100%
working_with_data/ca_dictionaries/dict_dispatch 23 0 100%
working_with_data/ca_dictionaries/dict_get_default 10 1 90%
working_with_data/ca_dictionaries/dictionary_comprehensions 21 0 100%
working_with_data/cb_sets/make_use_of_mathematical_set_operations 25 0 100%
working_with_data/cb_sets/set_comprehensions 12 0 100%
working_with_data/cb_sets/use_sets_to_remove_duplicates 34 6 82%
working_with_data/cc_tuples/named_tuples 26 0 100%
working_with_data/cc_tuples/tuple_underscore 15 0 100%
working_with_data/cc_tuples/tuples 12 0 100%
working_with_data/classes/2only/2only_prepend_private_data_with_underscore 43 43 0%
working_with_data/classes/2only/2only_use_str_for_human_readable_class_representation 18 18 0%
working_with_data/classes/3only/3only_prepend_private_data_with_underscore 45 2 96%
working_with_data/classes/3only/3only_use_str_for_human_readable_class_representation 18 0 100%
working_with_data/context_managers/context_managers 16 7 56%
working_with_data/generators/use_generator_expression_for_iteration 16 0 100%
working_with_data/generators/use_generators_to_lazily_load_sequences 44 1 98%
------------------------------------------------------------------------------------------------------------------
TOTAL 849 146 83%
============================================================ 150 passed in 1.73 seconds ============================================================
_____________________________________________________________________ summary ______________________________________________________________________
py33verbose: commands succeeded
congratulations :)
结果很可怕啊。
setuptools整合
tox可以和setuptools整合,这样python的setup.py测试可以运行你的tox测试。将下面的代码段放到你的setup.py文件里,这段代码是直接从tox的文档里拿来的:
from setuptools.command.test import test as TestCommand
import sys
class Tox(TestCommand):
def finalize_options(self):
TestCommand.finalize_options(self)
self.test_args = []
self.test_suite = True
def run_tests(self):
#import here, cause outside the eggs aren't loaded
import tox
errcode = tox.cmdline(self.test_args)
sys.exit(errcode)
setup(
#...,
tests_require=['tox'],
cmdclass = {'test': Tox},
)
现在Python的setup.py测试将下载tox并运行它。真的很酷并且很节省时间。