Welcome to Python wrap cases’s documentation!¶
Contents:
Python wrap cases¶
Simple library for generate test cases with parameters.
What is this?¶
This library helps to generate tests with parameters.
Let’s write some tests for this function:
import re
def clear_start_end_dash(string):
return re.sub(r'^[\s\-]*-|-[\s\-]*$', '', string)
We may write something like this:
from unittest import TestCase
class ClearStartEndDashTest(TestCase):
def test_remove_first_dash(self):
result = clear_start_end_dash('-my string')
self.assertEqual(result, 'my string')
def test_remove_all_first_dashes(self):
result = clear_start_end_dash('- -- --my string')
self.assertEqual(result, 'my string')
def test_remove_last_dash(self):
result = clear_start_end_dash('my string-')
self.assertEqual(result, 'my string')
def test_remove_all_last_dashes(self):
result = clear_start_end_dash('my string-- -- -- - ')
self.assertEqual(result, 'my string')
def test_keep_dash_at_center(self):
result = clear_start_end_dash('my-string')
self.assertEqual(result, 'my-string')
It’s good, but we spent a lot of time to write those absolutely the same test functions.
So let’s decrease the number of duplicate functions:
from unittest import TestCase
class ClearStartEndDashDryTest(TestCase):
def test_remove_dash(self):
cases = (
('-my string', 'my string'),
('- -- --my string', 'my string'),
('my string-', 'my string'),
('my string-- -- -- - ', 'my string'),
('my-string', 'my-string')
)
for string, expected_result in cases:
result = clear_start_end_dash(string)
self.assertEqual(result, expected_result)
This code has a few problems:
- Easy to write but difficult to read.
- We can’t use test fixture (setUp, tearDown) with each case.
- If some case fails, the other cases won’t run.
- If test test_remove_dash fails, it won’t help us find out what happened.
Look how easy we may solve these problems using this library:
from unittest import TestCase
from python_wrap_cases import wrap_case
@wrap_case
class ClearStartEndDashWrapTest(TestCase):
@wrap_case('-my string', 'my string')
@wrap_case('- -- --my string', 'my string')
@wrap_case('my string-', 'my string')
@wrap_case('my string-- -- -- - ', 'my string')
@wrap_case('my-string', 'my-string')
def test_remove_dash(self, string, expected_result):
result = clear_start_end_dash(string)
self.assertEqual(result, expected_result)
This code generates 5 tests, that works like a simple test functions.
Console output:
test_remove_dash_u'- -- --my string'_u'my string' (tests.example.test_simple_test.ClearStartEndDashWrapTest) ... ok
test_remove_dash_u'-my string'_u'my string' (tests.example.test_simple_test.ClearStartEndDashWrapTest) ... ok
test_remove_dash_u'my string-'_u'my string' (tests.example.test_simple_test.ClearStartEndDashWrapTest) ... ok
test_remove_dash_u'my string-- -- -- - '_u'my string' (tests.example.test_simple_test.ClearStartEndDashWrapTest) ... ok
test_remove_dash_u'my-string'_u'my-string' (tests.example.test_simple_test.ClearStartEndDashWrapTest) ... ok
Installation¶
pip install python_wrap_cases
Free software: BSD license
Documentation: https://python_wrap_cases.readthedocs.org.
Installation¶
At the command line:
$ easy_install python_wrap_cases
Or, if you have virtualenvwrapper installed:
$ mkvirtualenv python_wrap_cases
$ pip install python_wrap_cases
Usage¶
To use Python wrap cases in a project
from unittest import TestCase
from python_wrap_cases import wrap_case
@wrap_case
class SomeTest(TestCase):
@wrap_case('value1_a', 'value2_a')
@wrap_case('value1_b', 'value2_b')
def test_with_params(self, param1, param2)
# ...
Just add mixin WrapCasesMixin to your test class and add decorators @wrap_case to test function with parameters that you wanna add to test method.
Usage with mock¶
By default wrap_case detects the mock arguments and changes a return_value.
import unittest
from python_wrap_cases import wrap_case
from mock import patch
class TestedClass():
def foo_a(self):
pass
def foo_b(self):
pass
def tested_method(self):
return self.foo_a() + self.foo_b()
@wrap_case
class TestsWithMock(unittest.TestCase):
@wrap_case(2, 2, 4)
@wrap_case(3, 3, 6)
@wrap_case(4, 4, 8)
@patch.object(TestedClass, 'foo_b')
@patch.object(TestedClass, 'foo_a')
def test_with_patch_object(self, return_value):
tested_class = TestedClass()
self.assertEqual(tested_class.tested_method(), return_value)
@wrap_case(foo_a=2, result=4)
@wrap_case(foo_a=4, result=6)
@wrap_case(foo_a=8, result=10)
@patch.multiple(TestedClass, foo_a=DEFAULT, foo_b=DEFAULT)
def test_with_patch_multiple(self, result, foo_b):
foo_b.return_value = 2
tested_class = TestedClass()
self.assertEqual(tested_class.tested_method(), result)
ListGenerator¶
List generator helps to generate cases based on list of arguments.
import unittest
from python_wrap_cases import wrap_case
@wrap_case
class ListGeneratorTests(unittest.TestCase):
@wrap_case(number__list=[0, 1, 2, 3])
def test_div_1(self, number):
self.assertEqual(number/1, number)
This code will work like this one:
List generator helps to generate cases based on list of arguments.
import unittest
from python_wrap_cases import wrap_case
@wrap_case
class TestsWithoutListGenerator(unittest.TestCase):
@wrap_case(number=0)
@wrap_case(number=1)
@wrap_case(number=2)
@wrap_case(number=3)
def test_div_1(self, number):
self.assertEqual(number/1, number)
If you use two or more list generator in wrap_case, library will generate all possible combination of arguments from these lists.
import unittest
from python_wrap_cases import wrap_case
@wrap_case
class TestWithTwoListGenerators(unittest.TestCase):
@wrap_case(a__list=[1, 2], b__list=[0, 1])
def test_gte(self, a, b):
self.assertTrue(a >= b)
it’s equal to:
import unittest
from python_wrap_cases import wrap_case
@wrap_case
class TestWithoutListGenerators(unittest.TestCase):
@wrap_case(a=1, b=0)
@wrap_case(a=1, b=1)
@wrap_case(a=2, b=0)
@wrap_case(a=2, b=1)
def test_gte(self, a, b):
self.assertTrue(a >= b)
SyncListGenerator¶
The same as ListGenerator but instead of generate all possible argument combination it generate cases successively.
import unittest
from python_wrap_cases import wrap_case
@wrap_case
class TestWithSyncListGenerator(unittest.TestCase):
@wrap_case(number__sync_list=[0, 1, 2, 3], result__sync_list=[1, 2, 3, 4])
def test_add_1(self, number, result):
self.assertEqual(number + 1, result)
it’s equal to:
import unittest
from python_wrap_cases import wrap_case
@wrap_case
class TestWithoutSyncListGenerator(unittest.TestCase):
@wrap_case(number=0, result=1)
@wrap_case(number=1, result=2)
@wrap_case(number=2, result=3)
@wrap_case(number=3, result=4)
def test_add_1(self, number, result):
self.assertEqual(number + 1, result)
CustomGenerator¶
If you need more flexible generator you may use CustomGenerator
import unittest
from python_wrap_cases import wrap_case
@wrap_case
class CustomGenerators(unittest.TestCase):
@wrap_case(number__list=[0, 1, 2, 3], result__custom=lambda number, result: number + 1)
def test_add_1(self, number, result):
self.assertEqual(number + 1, result)
FuncGenerator¶
Simple as a CustomGenerator but without arguments.
import unittest
from python_wrap_cases import wrap_case
@wrap_case
class FuncGenerator(unittest.TestCase):
@wrap_case(string__func=lambda: 'Hello World{0}'.format('!'*3))
def test_simple_func(self, string):
self.assertEqual(string, 'Hello World!!!')
RangeGenerator¶
Generate range of numbers
import unittest
from python_wrap_cases import wrap_case
@wrap_case
class RangeGenerator(unittest.TestCase):
@wrap_case(number__range=4)
def test_range_4_div_1(self, number):
self.assertEqual(number/1, number)
@wrap_case(number__range=(1, 4, ))
def test_range_1_4_div_1(self, number):
self.assertEqual(number/1, number)
@wrap_case(number__range=(1, 4, 2, ))
def test_range_1_4_2_div_1(self, number):
self.assertEqual(number/1, number)
Contributing¶
Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given.
You can contribute in many ways:
Types of Contributions¶
Report Bugs¶
Report bugs at https://github.com/erm0l0v/python_wrap_cases/issues.
If you are reporting a bug, please include:
- Your operating system name and version.
- Any details about your local setup that might be helpful in troubleshooting.
- Detailed steps to reproduce the bug.
Fix Bugs¶
Look through the GitHub issues for bugs. Anything tagged with “bug” is open to whoever wants to implement it.
Implement Features¶
Look through the GitHub issues for features. Anything tagged with “feature” is open to whoever wants to implement it.
Write Documentation¶
Python wrap cases could always use more documentation, whether as part of the official Python wrap cases docs, in docstrings, or even on the web in blog posts, articles, and such.
Submit Feedback¶
The best way to send feedback is to file an issue at https://github.com/erm0l0v/python_wrap_cases/issues.
If you are proposing a feature:
- Explain in detail how it would work.
- Keep the scope as narrow as possible, to make it easier to implement.
- Remember that this is a volunteer-driven project, and that contributions are welcome :)
Get Started!¶
Ready to contribute? Here’s how to set up python_wrap_cases for local development.
Fork the python_wrap_cases repo on GitHub.
Clone your fork locally:
$ git clone git@github.com:your_name_here/python_wrap_cases.git
Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:
$ mkvirtualenv python_wrap_cases $ cd python_wrap_cases/ $ python setup.py develop
Create a branch for local development:
$ git checkout -b name-of-your-bugfix-or-feature
Now you can make your changes locally.
When you’re done making changes, check that your changes pass flake8 and the tests, including testing other Python versions with tox:
$ flake8 python_wrap_cases tests $ python setup.py test $ tox
To get flake8 and tox, just pip install them into your virtualenv.
Commit your changes and push your branch to GitHub:
$ git add . $ git commit -m "Your detailed description of your changes." $ git push origin name-of-your-bugfix-or-feature
Submit a pull request through the GitHub website.
Pull Request Guidelines¶
Before you submit a pull request, check that it meets these guidelines:
- The pull request should include tests.
- If the pull request adds functionality, the docs should be updated. Put your new functionality into a function with a docstring, and add the feature to the list in README.rst.
- The pull request should work for Python 2.6, 2.7, 3.3, and 3.4, and for PyPy. Check https://travis-ci.org/erm0l0v/python_wrap_cases/pull_requests and make sure that the tests pass for all supported Python versions.
Credits¶
Development Lead¶
- Kirill Ermolov <erm0l0v@ya.ru>
Contributors¶
None yet. Why not be the first?
History¶
0.1.0 (2015-06-26)¶
- First release on PyPI.
0.1.2 (2015-06-26)¶
- Fix generators import
0.1.3 (2015-06-26)¶
- Add some docs
0.1.4 (2015-06-29)¶
- ReadMe add semicolon
- Fix pypi readme
0.1.5 (2015-07-01)¶
- README remove ::;
0.1.6 (2015-07-01)¶
- Add tests fot python 3.2
0.1.7 (2015-07-10)¶
- Add six dependency
0.1.8 (2015-08-21)¶
- Add func generator
- Add range generator
- Fix problem with iterator in custom generator
- Add new API for declaration wrapped TestCase. (added wrap_case decorator without parameters)