Skip to content

Commit

Permalink
pytest_plugin #13(#448)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexeySanko committed Oct 15, 2017
1 parent d0f8f80 commit 8dae883
Show file tree
Hide file tree
Showing 9 changed files with 378 additions and 39 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# -*- coding: utf-8 -*-
#
# This file is part of PyBuilder
#
# Copyright 2011-2015 PyBuilder Team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from os import sep as os_sep
import unittest

from integrationtest_support import IntegrationTestSupport
from pybuilder.errors import BuildFailedException


failure_pytest_test_content = """
def test_pytest_base_failure():
assert False
"""


class TestDefaultParamFailure(IntegrationTestSupport):
def test_pytest(self):
self.write_build_file("""
from pybuilder.core import use_plugin, init
use_plugin("python.pytest")
@init
def init (project):
pass
""")

unittest_path = "src/unittest/python"
unittest_file = unittest_path + os_sep + "failure_test.py"
report_file = "target/reports/junit.xml"

self.create_directory(unittest_path)
self.write_file(unittest_file, failure_pytest_test_content)

reactor = self.prepare_reactor()
self.assertRaises(BuildFailedException, reactor.build, "run_unit_tests")

self.assert_file_exists(unittest_file)
self.assert_file_exists(report_file)

self.assert_file_contains(report_file, 'tests="1"')
self.assert_file_contains(report_file, 'errors="0"')
self.assert_file_contains(report_file, 'failures="1"')
self.assert_file_contains(report_file, 'skips="0"')


if __name__ == "__main__":
unittest.main()
69 changes: 69 additions & 0 deletions src/integrationtest/python/should_run_pytest_plugin_tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# -*- coding: utf-8 -*-
#
# This file is part of PyBuilder
#
# Copyright 2011-2015 PyBuilder Team
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from os import sep as os_sep
import unittest

from integrationtest_support import IntegrationTestSupport


success_pytest_test_content = """
def test_pytest_base_success():
assert True
def test_pytest_base_skip():
assert True
"""


class TestCustomParamSuccess(IntegrationTestSupport):
def test_pytest(self):
self.write_build_file("""
from pybuilder.core import use_plugin, init
use_plugin("python.pytest")
@init
def init (project):
project.set_property("dir_source_pytest_python", "some_dir/unittest")
project.set_property("pytest_report_file", "some_dir/junit.xml")
project.get_property("pytest_extra_args").append("-k")
project.get_property("pytest_extra_args").append("test_pytest_base_success")
""")

unittest_path = "some_dir/unittest"
unittest_file = unittest_path + os_sep + "success_test.py"
report_file = "some_dir/junit.xml"

self.create_directory(unittest_path)
self.write_file(unittest_file, success_pytest_test_content)

reactor = self.prepare_reactor()
reactor.build("run_unit_tests")

self.assert_file_exists(unittest_file)
self.assert_file_exists(report_file)

self.assert_file_contains(report_file, 'tests="1"')
self.assert_file_contains(report_file, 'errors="0"')
self.assert_file_contains(report_file, 'failures="0"')
self.assert_file_contains(report_file, 'skips="0"')


if __name__ == "__main__":
unittest.main()
15 changes: 14 additions & 1 deletion src/main/python/pybuilder/plugins/python/coverage_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,14 @@ def _delete_non_essential_modules():
for module_name in list(sys.modules.keys()):
module = sys.modules[module_name]
if module:
if not _is_module_essential(module.__name__, sys_packages, sys_modules):
try:
# if we try to remove non-module object
module__name__ = module.__name__
except:
module__name__ = None
if module__name__ is None:
module__name__ = module_name
if not _is_module_essential(module__name__, sys_packages, sys_modules):
_delete_module(module_name, module)


Expand All @@ -326,6 +333,9 @@ def _delete_module(module_name, module):
delattr(module, module_name)
except AttributeError:
pass
# if we try to remove non-class object
except ImportError:
pass


def _is_module_essential(module_name, sys_packages, sys_modules):
Expand All @@ -338,6 +348,9 @@ def _is_module_essential(module_name, sys_packages, sys_modules):
# Essential since we're in a fork for communicating exceptions back
sys_packages.append("tblib")
sys_packages.append("pybuilder.errors")
# External modules
sys_packages.append("pkg_resources")
sys_packages.append("_pytest")

for package in sys_packages:
if module_name == package or module_name.startswith(package + "."):
Expand Down
70 changes: 70 additions & 0 deletions src/main/python/pybuilder/plugins/python/pytest_plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# -*- coding: utf-8 -*-
#
# Copyright 2016 Alexey Sanko
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from sys import path as sys_path

from pybuilder.core import task, init, use_plugin, after
from pybuilder.errors import MissingPrerequisiteException, BuildFailedException
from pybuilder.utils import register_test_and_source_path_and_return_test_dir

__author__ = 'Alexey Sanko'

use_plugin("python.core")


@init
def initialize_pytest_plugin(project):
""" Init default plugin project properties. """
project.plugin_depends_on('pytest')
project.set_property_if_unset("dir_source_pytest_python", "src/unittest/python")
project.set_property_if_unset("pytest_report_file", "target/reports/junit.xml")
project.set_property_if_unset("pytest_extra_args", [])


@after("prepare")
def assert_pytest_available(logger):
""" Asserts that the pytest module is available. """
logger.debug("Checking if pytest module is available.")

try:
import pytest
logger.debug("Found pytest version %s" % pytest.__version__)
except ImportError:
raise MissingPrerequisiteException(prerequisite="pytest module", caller="plugin python.pytest")


@task
def run_unit_tests(project, logger):
""" Call pytest for the sources of the given project. """
logger.info('pytest: Run unittests.')
from pytest import main as pytest_main
test_dir = register_test_and_source_path_and_return_test_dir(project, sys_path, 'pytest')
extra_args = project.get_property("pytest_extra_args")
try:
pytest_args = [test_dir]
if project.get_property('verbose'):
pytest_args.append('-s')
pytest_args.append('-v')
pytest_args.append('--junit-xml')
pytest_args.append(project.expand_path('$pytest_report_file'))
pytest_args = pytest_args + (extra_args if extra_args else [])
ret = pytest_main(pytest_args)
if ret:
raise BuildFailedException('pytest: unittests failed')
else:
logger.info('pytest: All unittests passed.')
except:
raise
15 changes: 5 additions & 10 deletions src/main/python/pybuilder/plugins/python/unittest_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,10 @@

from pybuilder.core import init, task, description, use_plugin
from pybuilder.errors import BuildFailedException
from pybuilder.utils import discover_modules_matching, render_report, fork_process
from pybuilder.utils import (discover_modules_matching,
render_report,
fork_process,
register_test_and_source_path_and_return_test_dir)
from pybuilder.ci_server_interaction import test_proxy_for
from pybuilder.terminal import print_text_line
from types import MethodType, FunctionType
Expand Down Expand Up @@ -72,7 +75,7 @@ def run_tests(project, logger, execution_prefix, execution_name):


def do_run_tests(project, logger, execution_prefix, execution_name):
test_dir = _register_test_and_source_path_and_return_test_dir(project, sys.path, execution_prefix)
test_dir = register_test_and_source_path_and_return_test_dir(project, sys.path, execution_prefix)

file_suffix = project.get_property("%s_file_suffix" % execution_prefix)
if file_suffix is not None:
Expand Down Expand Up @@ -197,14 +200,6 @@ def addFailure(self, test, err):
return result


def _register_test_and_source_path_and_return_test_dir(project, system_path, execution_prefix):
test_dir = project.expand_path("$dir_source_%s_python" % execution_prefix)
system_path.insert(0, test_dir)
system_path.insert(0, project.expand_path("$dir_source_main_python"))

return test_dir


def write_report(name, project, logger, result, console_out):
project.write_report("%s" % name, console_out)

Expand Down
7 changes: 7 additions & 0 deletions src/main/python/pybuilder/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,3 +348,10 @@ def safe_log_file_name(file_name):
# per https://support.microsoft.com/en-us/kb/177506
# per https://msdn.microsoft.com/en-us/library/aa365247
return re.sub(r'\\|/|:|\*|\?|\"|<|>|\|', '_', file_name)


def register_test_and_source_path_and_return_test_dir(project, system_path, execution_prefix):
test_dir = project.expand_path("$dir_source_%s_python" % execution_prefix)
system_path.insert(0, test_dir)
system_path.insert(0, project.expand_path("$dir_source_main_python"))
return test_dir

0 comments on commit 8dae883

Please sign in to comment.