aboutsummaryrefslogtreecommitdiff
path: root/tasks/test.py
diff options
context:
space:
mode:
Diffstat (limited to 'tasks/test.py')
-rw-r--r--tasks/test.py207
1 files changed, 207 insertions, 0 deletions
diff --git a/tasks/test.py b/tasks/test.py
new file mode 100644
index 0000000..f1c4991
--- /dev/null
+++ b/tasks/test.py
@@ -0,0 +1,207 @@
+# -*- coding: UTF-8 -*-
+"""
+Invoke test tasks.
+"""
+
+from __future__ import print_function
+import os.path
+import sys
+from invoke import task, Collection
+
+# -- TASK-LIBRARY:
+from ._tasklet_cleanup import cleanup_tasks, cleanup_dirs, cleanup_files
+
+
+# ---------------------------------------------------------------------------
+# CONSTANTS:
+# ---------------------------------------------------------------------------
+USE_BEHAVE = False
+
+
+# ---------------------------------------------------------------------------
+# TASKS
+# ---------------------------------------------------------------------------
+@task(name="all", help={
+ "args": "Command line args for test run.",
+})
+def test_all(ctx, args="", options=""):
+ """Run all tests (default)."""
+ pytest_args = select_by_prefix(args, ctx.pytest.scopes)
+ behave_args = None
+ if USE_BEHAVE:
+ behave_args = select_by_prefix(args, ctx.behave_test.scopes)
+ pytest_should_run = not args or (args and pytest_args)
+ behave_should_run = not args or (args and behave_args)
+ if pytest_should_run:
+ pytest(ctx, pytest_args, options=options)
+ if behave_should_run and USE_BEHAVE:
+ behave(ctx, behave_args, options=options)
+
+
+@task
+def clean(ctx, dry_run=False):
+ """Cleanup (temporary) test artifacts."""
+ directories = ctx.test.clean.directories or []
+ files = ctx.test.clean.files or []
+ cleanup_dirs(directories, dry_run=dry_run)
+ cleanup_files(files, dry_run=dry_run)
+
+
+@task(name="unit")
+def unittest(ctx, args="", options=""):
+ """Run unit tests."""
+ pytest(ctx, args, options)
+
+
+@task
+def pytest(ctx, args="", options=""):
+ """Run unit tests."""
+ args = args or ctx.pytest.args
+ options = options or ctx.pytest.options
+ ctx.run("pytest {options} {args}".format(options=options, args=args))
+
+
+@task(help={
+ "args": "Command line args for behave",
+ "format": "Formatter to use (progress, pretty, ...)",
+})
+def behave(ctx, args="", format="", options=""):
+ """Run behave tests."""
+ format = format or ctx.behave_test.format
+ options = options or ctx.behave_test.options
+ args = args or ctx.behave_test.args
+ if os.path.exists("bin/behave"):
+ behave_cmd = "{python} bin/behave".format(python=sys.executable)
+ else:
+ behave_cmd = "{python} -m behave".format(python=sys.executable)
+
+ for group_args in grouped_by_prefix(args, ctx.behave_test.scopes):
+ ctx.run("{behave} -f {format} {options} {args}".format(
+ behave=behave_cmd, format=format, options=options, args=group_args))
+
+
+@task(help={
+ "args": "Tests to run (empty: all)",
+ "report": "Coverage report format to use (report, html, xml)",
+})
+def coverage(ctx, args="", report="report", append=False):
+ """Determine test coverage (run pytest, behave)"""
+ append = append or ctx.coverage.append
+ report_formats = ctx.coverage.report_formats or []
+ if report not in report_formats:
+ report_formats.insert(0, report)
+ opts = []
+ if append:
+ opts.append("--append")
+
+ pytest_args = select_by_prefix(args, ctx.pytest.scopes)
+ behave_args = select_by_prefix(args, ctx.behave_test.scopes)
+ pytest_should_run = not args or (args and pytest_args)
+ behave_should_run = not args or (args and behave_args) and USE_BEHAVE
+ if not args:
+ behave_args = ctx.behave_test.args or "features"
+ if isinstance(pytest_args, list):
+ pytest_args = " ".join(pytest_args)
+ if isinstance(behave_args, list):
+ behave_args = " ".join(behave_args)
+
+ # -- RUN TESTS WITH COVERAGE:
+ if pytest_should_run:
+ ctx.run("coverage run {options} -m pytest {args}".format(
+ args=pytest_args, options=" ".join(opts)))
+ if behave_should_run and USE_BEHAVE:
+ behave_options = ctx.behave_test.coverage_options or ""
+ os.environ["COVERAGE_PROCESS_START"] = os.path.abspath(".coveragerc")
+ behave(ctx, args=behave_args, options=behave_options)
+ del os.environ["COVERAGE_PROCESS_START"]
+
+ # -- POST-PROCESSING:
+ ctx.run("coverage combine")
+ for report_format in report_formats:
+ ctx.run("coverage {report_format}".format(report_format=report_format))
+
+
+# ---------------------------------------------------------------------------
+# UTILITIES:
+# ---------------------------------------------------------------------------
+def select_prefix_for(arg, prefixes):
+ for prefix in prefixes:
+ if arg.startswith(prefix):
+ return prefix
+ return os.path.dirname(arg)
+
+
+def select_by_prefix(args, prefixes):
+ selected = []
+ for arg in args.strip().split():
+ assert not arg.startswith("-"), "REQUIRE: arg, not options"
+ scope = select_prefix_for(arg, prefixes)
+ if scope:
+ selected.append(arg)
+ return " ".join(selected)
+
+
+def grouped_by_prefix(args, prefixes):
+ """Group behave args by (directory) scope into multiple test-runs."""
+ group_args = []
+ current_scope = None
+ for arg in args.strip().split():
+ assert not arg.startswith("-"), "REQUIRE: arg, not options"
+ scope = select_prefix_for(arg, prefixes)
+ if scope != current_scope:
+ if group_args:
+ # -- DETECTED GROUP-END:
+ yield " ".join(group_args)
+ group_args = []
+ current_scope = scope
+ group_args.append(arg)
+ if group_args:
+ yield " ".join(group_args)
+
+
+# ---------------------------------------------------------------------------
+# TASK MANAGEMENT / CONFIGURATION
+# ---------------------------------------------------------------------------
+namespace = Collection(clean, unittest, pytest, coverage)
+namespace.add_task(test_all, default=True)
+if USE_BEHAVE:
+ namespace.add_task(behave)
+
+namespace.configure({
+ "test": {
+ "clean": {
+ "directories": [
+ ".cache", "assets", # -- TEST RUNS
+ # -- BEHAVE-SPECIFIC:
+ "__WORKDIR__", "reports", "test_results",
+ ],
+ "files": [
+ ".coverage", ".coverage.*",
+ # -- BEHAVE-SPECIFIC:
+ "report.html",
+ "rerun*.txt", "rerun*.featureset", "testrun*.json",
+ ],
+ },
+ },
+ "pytest": {
+ "scopes": ["tests"],
+ "args": "",
+ "options": "", # -- NOTE: Overide in configfile "invoke.yaml"
+ },
+ # "behave_test": behave.namespace._configuration["behave_test"],
+ "behave_test": {
+ "scopes": ["features"],
+ "args": "features",
+ "format": "progress",
+ "options": "", # -- NOTE: Overide in configfile "invoke.yaml"
+ "coverage_options": "",
+ },
+ "coverage": {
+ "append": False,
+ "report_formats": ["report", "html"],
+ },
+})
+
+# -- ADD CLEANUP TASK:
+cleanup_tasks.add_task(clean, "clean_test")
+cleanup_tasks.configure(namespace.configuration())