-
Notifications
You must be signed in to change notification settings - Fork 56
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
227 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# pytest-testslide | ||
|
||
TestSlide fixture for pytest. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# Copyright (c) Facebook, Inc. and its affiliates. | ||
# | ||
# This source code is licensed under the MIT license found in the | ||
# LICENSE file in the root directory of this source tree. | ||
|
||
from types import TracebackType | ||
from typing import Any, Callable, Iterator, List, Optional | ||
|
||
import pytest # type: ignore | ||
|
||
import testslide as testslide_module | ||
|
||
|
||
class _TestSlideFixture: | ||
def _register_assertion(self, assertion: Callable) -> None: | ||
self._assertions.append(assertion) | ||
|
||
def __enter__(self) -> "_TestSlideFixture": | ||
self._assertions: List[Callable] = [] | ||
testslide_module.mock_callable.register_assertion = self._register_assertion | ||
return self | ||
|
||
def __exit__( | ||
self, | ||
exc_type: Optional[type], | ||
exc_val: Optional[Exception], | ||
exc_tb: TracebackType, | ||
): | ||
aggregated_exceptions = testslide_module.AggregatedExceptions() | ||
try: | ||
for assertion in self._assertions: | ||
try: | ||
assertion() | ||
except BaseException as be: | ||
aggregated_exceptions.append_exception(be) | ||
|
||
finally: | ||
testslide_module.mock_callable.unpatch_all_callable_mocks() | ||
testslide_module.mock_constructor.unpatch_all_constructor_mocks() | ||
testslide_module.patch_attribute.unpatch_all_mocked_attributes() | ||
if aggregated_exceptions.exceptions: | ||
pytest.fail(str(aggregated_exceptions), False) | ||
|
||
@staticmethod | ||
def mock_callable( | ||
*args: Any, **kwargs: Any | ||
) -> testslide_module.mock_callable._MockCallableDSL: | ||
return testslide_module.mock_callable.mock_callable(*args, **kwargs) | ||
|
||
@staticmethod | ||
def mock_async_callable( | ||
*args: Any, **kwargs: Any | ||
) -> testslide_module.mock_callable._MockAsyncCallableDSL: | ||
return testslide_module.mock_callable.mock_async_callable(*args, **kwargs) | ||
|
||
@staticmethod | ||
def mock_constructor( | ||
*args: Any, **kwargs: Any | ||
) -> testslide_module.mock_constructor._MockConstructorDSL: | ||
return testslide_module.mock_constructor.mock_constructor(*args, **kwargs) | ||
|
||
@staticmethod | ||
def patch_attribute(*args: Any, **kwargs: Any) -> None: | ||
return testslide_module.patch_attribute.patch_attribute(*args, **kwargs) | ||
|
||
|
||
@pytest.fixture | ||
def testslide() -> Iterator[_TestSlideFixture]: | ||
with _TestSlideFixture() as testslide_fixture: | ||
yield testslide_fixture |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# Copyright (c) Facebook, Inc. and its affiliates. | ||
# | ||
# This source code is licensed under the MIT license found in the | ||
# LICENSE file in the root directory of this source tree. | ||
|
||
from setuptools import setup # type: ignore | ||
|
||
with open("README.md", encoding="utf8") as f: | ||
readme = f.read() | ||
|
||
setup( | ||
name="pytest-testslide", | ||
version="1.0.0", | ||
py_modules=["pytest_testslide"], | ||
maintainer="Fabio Pugliese Ornellas", | ||
maintainer_email="fabio.ornellas@gmail.com", | ||
url="https://github.com/facebookincubator/TestSlide", | ||
license="MIT", | ||
description="TestSlide fixture for pytest", | ||
long_description=readme, | ||
long_description_content_type="text/markdown", | ||
setup_requires=["setuptools>=38.6.0"], | ||
install_requires=[ | ||
"testslide>=2.2.1", | ||
"pytest>=5.3.0", | ||
], | ||
extras_require={"build": ["black", "flake8", "mypy"]}, | ||
classifiers=[ | ||
"Development Status :: 5 - Production/Stable", | ||
"Intended Audience :: Developers", | ||
"License :: OSI Approved :: MIT License", | ||
"Operating System :: POSIX :: Linux", | ||
"Programming Language :: Python :: 3", | ||
"Topic :: Software Development :: Testing", | ||
"Topic :: Software Development :: Testing :: Acceptance", | ||
"Topic :: Software Development :: Testing :: BDD", | ||
"Topic :: Software Development :: Testing :: Mocking", | ||
"Topic :: Software Development :: Testing :: Unit ", | ||
], | ||
entry_points={"pytest11": ["pytest-testslide = pytest_testslide"]}, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# Copyright (c) Facebook, Inc. and its affiliates. | ||
# | ||
# This source code is licensed under the MIT license found in the | ||
# LICENSE file in the root directory of this source tree. | ||
|
||
pytest_plugins = "pytester" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
# Copyright (c) Facebook, Inc. and its affiliates. | ||
# | ||
# This source code is licensed under the MIT license found in the | ||
# LICENSE file in the root directory of this source tree. | ||
import re | ||
|
||
|
||
def test_pass(testdir): | ||
testdir.makepyfile( | ||
""" | ||
import time | ||
import pytest | ||
from pytest_testslide import testslide | ||
from tests import sample_module | ||
from testslide import StrictMock | ||
def test_has_mock_callable(testslide): | ||
testslide.mock_callable | ||
def test_mock_callable_assertion_works(testslide): | ||
testslide.mock_callable | ||
def test_mock_callable_unpaches(testslide): | ||
testslide.mock_callable | ||
def test_has_mock_async_callable(testslide): | ||
testslide.mock_async_callable | ||
def test_mock_async_callable_assertion_works(testslide): | ||
testslide.mock_async_callable | ||
def test_mock_async_callable_unpaches(testslide): | ||
testslide.mock_async_callable | ||
def test_has_mock_constructor(testslide): | ||
testslide.mock_constructor | ||
def test_mock_constructor_assertion_works(testslide): | ||
testslide.mock_constructor | ||
def test_mock_constructor_unpaches(testslide): | ||
testslide.mock_constructor | ||
def test_has_patch_attribute(testslide): | ||
testslide.patch_attribute | ||
def test_patch_attribute_unpaches(testslide): | ||
testslide.patch_attribute | ||
def test_mock_callable_patching_works(testslide): | ||
testslide.mock_callable("time", "sleep").to_raise(RuntimeError("Mocked!")) | ||
with pytest.raises(RuntimeError): | ||
time.sleep() | ||
def test_mock_callable_unpatching_works(testslide): | ||
# This will fail if unpatching from test_mock_callable_patching_works does | ||
# not happen | ||
time.sleep(0) | ||
def test_mock_callable_assertion_works(testslide): | ||
testslide.mock_callable("time", "sleep").for_call(0).to_call_original().and_assert_called_once() | ||
time.sleep(0) | ||
def test_mock_callable_failed_assertion_works(testslide): | ||
testslide.mock_callable("time", "sleep").for_call(0).to_call_original().and_assert_called_once() | ||
time.sleep(0) | ||
def test_aggregated_exceptions(testslide): | ||
mocked_cls = StrictMock(sample_module.CallOrderTarget) | ||
testslide.mock_callable(mocked_cls, 'f1')\ | ||
.for_call("a").to_return_value("mocked")\ | ||
.and_assert_called_once() | ||
testslide.mock_callable(mocked_cls, 'f1')\ | ||
.for_call("b").to_return_value("mocked2")\ | ||
.and_assert_called_once() | ||
sample_module.CallOrderTarget("c").f1("a") | ||
""" | ||
) | ||
result = testdir.runpytest("-v") | ||
assert "passed, 1 error" in result.stdout.str() | ||
expected_failure = re.compile( | ||
""".*_______________ ERROR at teardown of test_aggregated_exceptions ________________ | ||
2 failures. | ||
<class \'AssertionError\'>: calls did not match assertion. | ||
<StrictMock 0x[a-fA-F0-9]+ template=tests.sample_module.CallOrderTarget .*/test_pass0/test_pass.py:[0-9]+>, \'f1\': | ||
expected: called exactly 1 time\(s\) with arguments: | ||
\(\'a\',\) | ||
received: 0 call\(s\) | ||
<class \'AssertionError\'>: calls did not match assertion. | ||
<StrictMock 0x[a-fA-F0-9]+ template=tests.sample_module.CallOrderTarget .*/test_pass0/test_pass.py:[0-9]+>, \'f1\': | ||
expected: called exactly 1 time\(s\) with arguments: | ||
\(\'b\',\) | ||
received: 0 call\(s\).*""", | ||
re.MULTILINE | re.DOTALL, | ||
) | ||
assert expected_failure.match(result.stdout.str()) | ||
assert result.ret != 0 |