Add support for attachments to test execution (#3982)

* Add support for attachments to test execution

By default in CI and with tox locally we run all the tests in parallel.
However, this makes things like printing to stdout, warnings on stderr,
or logging during tests difficult to deal with. This is because we'll
have multiple writers to the output streams simultaneously and no way
to figure out which text goes to which test. Luckily stestr and the
subunit protocl it uses internally has a method for adding attachments
to test results to handle this kind of case. Using this each output
stream is associated with the test which generated it and will get
displayed as such. The only issue with this is that the stdlib unittest
doesn't know how to write attachments to it's result stream. There is a
unittest extension library testtools[1] that provides this functionality
in a strictly compatible manner with unittest, however the current state
of the library needs some work before it can work well with more modern
features of stdlib unittest from python>3.5 so we either have to change
the tests to not use these features or come up with an alternative
solution for test attachments.

This commit ports the necessary result streaming functionality from
testtools into the QiskitTestCase base test class and then sets up the
appropriate fixtures to attach output streams from each test. This works
around the current limitation with testtools (I'm slowly working on
fixing this in testtools) but still provides the functionality. When
testtools is at the point it can be a drop in replacement for unittest
as terra is using it we can drop this code.

As part of this change all the test classes that define a setUp have a
missing super() call added. This framework does not work without setUp
in the base class being defined since that's what is used to setup the
stream capture. Moving forward the base test class actually enforces
that super() is called, otherwise the tests will fail.

[1] https://github.com/testing-cabal/testtools

* Fix lint

* Update contributing doc

* Fix copy paste error

* Add missing super calls from new tests

* Add missing super() calls and fix skip message

* Fix lint

Co-authored-by: Luciano Bello <luciano.bello@ibm.com>
This commit is contained in:
Matthew Treinish 2020-09-09 19:01:54 -04:00 committed by GitHub
parent 3eafd2bc52
commit 01ded73d1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
60 changed files with 675 additions and 18 deletions

View File

@ -46,6 +46,7 @@ jobs:
python: 3.6
env:
- PYTHON="coverage run --source qiskit --parallel-mode"
- QISKIT_TEST_CAPTURE_STREAMS=1
after_success:
- coverage combine || true
- coveralls || true

View File

@ -280,6 +280,16 @@ C:\..\> set LOG_LEVEL="INFO"
C:\..\> python -m unittest test/python/circuit/test_circuit_operations.py
```
##### STDOUT/STDERR and logging capture
When running tests in parallel either via tox, the makefile, or in CI we set
the env variable `QISKIT_TEST_CAPTURE_STREAMS` which will capture any text
written to stdout, stderr, and log messages and add them as attachments to
the tests run so output can be associated with the test case it originated
from. However, if you run tests outside of these mechanisms by default the
streams are not captured. To enable stream capture just set the
`QISKIT_TEST_CAPTURE_STREAMS` env variable to `1`.
##### Test Skip Options
How and which tests are executed is controlled by an environment

View File

@ -67,7 +67,7 @@ pytest_randomized:
test_ci:
echo "Detected $(NPROCS) CPUs running with $(CONCURRENCY) workers"
stestr run --concurrency $(CONCURRENCY)
QISKIT_TEST_CAPTURE_STREAMS=1 stestr run --concurrency $(CONCURRENCY)
test_randomized:
python3 -m unittest discover -s test/randomized -t . -v

View File

@ -132,6 +132,7 @@ stages:
variables:
QISKIT_SUPPRESS_PACKAGING_WARNINGS: Y
PIP_CACHE_DIR: $(Pipeline.Workspace)/.pip
QISKIT_TEST_CAPTURE_STREAMS: 1
steps:
- task: UsePythonVersion@0
inputs:
@ -285,6 +286,7 @@ stages:
variables:
QISKIT_SUPPRESS_PACKAGING_WARNINGS: Y
PIP_CACHE_DIR: $(Pipeline.Workspace)/.pip
QISKIT_TEST_CAPTURE_STREAMS: 1
steps:
- task: UsePythonVersion@0
inputs:
@ -358,6 +360,7 @@ stages:
variables:
QISKIT_SUPPRESS_PACKAGING_WARNINGS: Y
PIP_CACHE_DIR: $(Pipeline.Workspace)/.pip
QISKIT_TEST_CAPTURE_STREAMS: 1
steps:
- task: UsePythonVersion@0
inputs:
@ -426,6 +429,7 @@ stages:
variables:
QISKIT_SUPPRESS_PACKAGING_WARNINGS: Y
PIP_CACHE_DIR: $(Pipeline.Workspace)/.pip
QISKIT_TEST_CAPTURE_STREAMS: 1
steps:
- task: UsePythonVersion@0
inputs:
@ -495,6 +499,7 @@ stages:
variables:
QISKIT_SUPPRESS_PACKAGING_WARNINGS: Y
PIP_CACHE_DIR: $(Pipeline.Workspace)/.pip
QISKIT_TEST_CAPTURE_STREAMS: 1
steps:
- task: UsePythonVersion@0
inputs:

View File

@ -10,6 +10,9 @@
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
# pylint: disable=attribute-defined-outside-init,invalid-name,missing-type-doc
# pylint: disable=unused-argument,broad-except,bad-staticmethod-argument
"""Base TestCases for the unit tests.
Implementors of unit tests for Terra are encouraged to subclass
@ -18,39 +21,316 @@ the environment variables for customizing different options), and the
decorators in the ``decorators`` package.
"""
import inspect
import itertools
import logging
import os
import sys
import unittest
from unittest.util import safe_repr
from .utils import Path, _AssertNoLogsContext, setup_test_logging
import fixtures
from testtools.compat import advance_iterator
from testtools import content
from .runtest import RunTest, MultipleExceptions
from .utils import Path, _AssertNoLogsContext
__unittest = True # Allows shorter stack trace for .assertDictAlmostEqual
def _copy_content(content_object):
"""Make a copy of the given content object.
The content within ``content_object`` is iterated and saved. This is
useful when the source of the content is volatile, a log file in a
temporary directory for example.
Args:
content_object (content.Content): A ``content.Content`` instance.
Returns:
content.Content: An instance with the same mime-type as
``content_object`` and a non-volatile copy of its content.
"""
content_bytes = list(content_object.iter_bytes())
def content_callback():
return content_bytes
return content.Content(content_object.content_type, content_callback)
def gather_details(source_dict, target_dict):
"""Merge the details from ``source_dict`` into ``target_dict``.
``gather_details`` evaluates all details in ``source_dict``. Do not use it
if the details are not ready to be evaluated.
:param source_dict: A dictionary of details will be gathered.
:param target_dict: A dictionary into which details will be gathered.
"""
for name, content_object in source_dict.items():
new_name = name
disambiguator = itertools.count(1)
while new_name in target_dict:
new_name = '%s-%d' % (name, advance_iterator(disambiguator))
name = new_name
target_dict[name] = _copy_content(content_object)
class QiskitTestCase(unittest.TestCase):
"""Helper class that contains common functionality."""
@classmethod
def setUpClass(cls):
# Determines if the TestCase is using IBMQ credentials.
cls.using_ibmq_credentials = False
run_tests_with = RunTest
# Set logging to file and stdout if the LOG_LEVEL envar is set.
cls.log = logging.getLogger(cls.__name__)
if os.getenv('LOG_LEVEL'):
filename = '%s.log' % os.path.splitext(inspect.getfile(cls))[0]
setup_test_logging(cls.log, os.getenv('LOG_LEVEL'), filename)
def __init__(self, *args, **kwargs):
"""Construct a TestCase."""
super(QiskitTestCase, self).__init__(*args, **kwargs)
self.__RunTest = self.run_tests_with
self._reset()
self.__exception_handlers = []
self.exception_handlers = [
(unittest.SkipTest, self._report_skip),
(self.failureException, self._report_failure),
(unittest.case._UnexpectedSuccess, self._report_unexpected_success),
(Exception, self._report_error)]
def _reset(self):
"""Reset the test case as if it had never been run."""
self._cleanups = []
self._unique_id_gen = itertools.count(1)
# Generators to ensure unique traceback ids. Maps traceback label to
# iterators.
self._traceback_id_gens = {}
self.__setup_called = False
self.__teardown_called = False
self.__details = None
def onException(self, exc_info, tb_label='traceback'):
"""Called when an exception propagates from test code.
:seealso addOnException:
"""
if exc_info[0] not in [
unittest.SkipTest, unittest.case._UnexpectedSuccess]:
self._report_traceback(exc_info, tb_label=tb_label)
for handler in self.__exception_handlers:
handler(exc_info)
def _run_teardown(self, result):
"""Run the tearDown function for this test."""
self.tearDown()
if not self.__teardown_called:
raise ValueError(
"In File: %s\n"
"TestCase.tearDown was not called. Have you upcalled all the "
"way up the hierarchy from your tearDown? e.g. Call "
"super(%s, self).tearDown() from your tearDown()."
% (sys.modules[self.__class__.__module__].__file__,
self.__class__.__name__))
def _get_test_method(self):
method_name = getattr(self, '_testMethodName')
return getattr(self, method_name)
def _run_test_method(self, result):
"""Run the test method for this test."""
return self._get_test_method()()
def useFixture(self, fixture):
"""Use fixture in a test case.
The fixture will be setUp, and self.addCleanup(fixture.cleanUp) called.
Args:
fixture: The fixture to use.
Returns:
fixture: The fixture, after setting it up and scheduling a cleanup
for it.
Raises:
MultipleExceptions: When there is an error during fixture setUp
Exception: If an exception is raised during fixture setUp
"""
try:
fixture.setUp()
except MultipleExceptions as e:
if (fixtures is not None and
e.args[-1][0] is fixtures.fixture.SetupError):
gather_details(e.args[-1][1].args[0], self.getDetails())
raise
except Exception:
exc_info = sys.exc_info()
try:
# fixture._details is not available if using the newer
# _setUp() API in Fixtures because it already cleaned up
# the fixture. Ideally this whole try/except is not
# really needed any more, however, we keep this code to
# remain compatible with the older setUp().
if (hasattr(fixture, '_details') and
fixture._details is not None):
gather_details(fixture.getDetails(), self.getDetails())
except Exception:
# Report the setUp exception, then raise the error during
# gather_details.
self._report_traceback(exc_info)
raise
else:
# Gather_details worked, so raise the exception setUp
# encountered.
def reraise(exc_class, exc_obj, exc_tb, _marker=object()):
"""Re-raise an exception received from sys.exc_info() or similar."""
raise exc_obj.with_traceback(exc_tb)
reraise(*exc_info)
else:
self.addCleanup(fixture.cleanUp)
self.addCleanup(
gather_details, fixture.getDetails(), self.getDetails())
return fixture
def _run_setup(self, result):
"""Run the setUp function for this test."""
self.setUp()
if not self.__setup_called:
raise ValueError(
"In File: %s\n"
"TestCase.setUp was not called. Have you upcalled all the "
"way up the hierarchy from your setUp? e.g. Call "
"super(%s, self).setUp() from your setUp()."
% (sys.modules[self.__class__.__module__].__file__,
self.__class__.__name__))
def _add_reason(self, reason):
self.addDetail('reason', content.text_content(reason))
@staticmethod
def _report_error(self, result, err):
result.addError(self, details=self.getDetails())
@staticmethod
def _report_expected_failure(self, result, err):
result.addExpectedFailure(self, details=self.getDetails())
@staticmethod
def _report_failure(self, result, err):
result.addFailure(self, details=self.getDetails())
@staticmethod
def _report_skip(self, result, err):
if err.args:
reason = err.args[0]
else:
reason = "no reason given."
self._add_reason(reason)
result.addSkip(self, details=self.getDetails())
def _report_traceback(self, exc_info, tb_label='traceback'):
id_gen = self._traceback_id_gens.setdefault(
tb_label, itertools.count(0))
while True:
tb_id = advance_iterator(id_gen)
if tb_id:
tb_label = '%s-%d' % (tb_label, tb_id)
if tb_label not in self.getDetails():
break
self.addDetail(tb_label, content.TracebackContent(
exc_info, self, capture_locals=getattr(
self, '__testtools_tb_locals__', False)))
@staticmethod
def _report_unexpected_success(self, result, err):
result.addUnexpectedSuccess(self, details=self.getDetails())
def run(self, result=None):
self._reset()
try:
run_test = self.__RunTest(
self, self.exception_handlers, last_resort=self._report_error)
except TypeError:
# Backwards compat: if we can't call the constructor
# with last_resort, try without that.
run_test = self.__RunTest(self, self.exception_handlers)
return run_test.run(result)
def setUp(self):
super().setUp()
if self.__setup_called:
raise ValueError(
"In File: %s\n"
"TestCase.setUp was already called. Do not explicitly call "
"setUp from your tests. In your own setUp, use super to call "
"the base setUp."
% (sys.modules[self.__class__.__module__].__file__,))
self.__setup_called = True
if os.environ.get('QISKIT_TEST_CAPTURE_STREAMS'):
stdout = self.useFixture(fixtures.StringStream('stdout')).stream
self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
stderr = self.useFixture(fixtures.StringStream('stderr')).stream
self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
self.useFixture(fixtures.LoggerFixture(nuke_handlers=False,
level=None))
def tearDown(self):
super().tearDown()
if self.__teardown_called:
raise ValueError(
"In File: %s\n"
"TestCase.tearDown was already called. Do not explicitly call "
"tearDown from your tests. In your own tearDown, use super to "
"call the base tearDown."
% (sys.modules[self.__class__.__module__].__file__,))
self.__teardown_called = True
# Reset the default providers, as in practice they acts as a singleton
# due to importing the instances from the top-level qiskit namespace.
from qiskit.providers.basicaer import BasicAer
BasicAer._backends = BasicAer._verify_backends()
def addDetail(self, name, content_object):
"""Add a detail to be reported with this test's outcome.
:param name: The name to give this detail.
:param content_object: The content object for this detail. See
testtools.content for more detail.
"""
if self.__details is None:
self.__details = {}
self.__details[name] = content_object
def addDetailUniqueName(self, name, content_object):
"""Add a detail to the test, but ensure it's name is unique.
This method checks whether ``name`` conflicts with a detail that has
already been added to the test. If it does, it will modify ``name`` to
avoid the conflict.
:param name: The name to give this detail.
:param content_object: The content object for this detail. See
testtools.content for more detail.
"""
existing_details = self.getDetails()
full_name = name
suffix = 1
while full_name in existing_details:
full_name = "%s-%d" % (name, suffix)
suffix += 1
self.addDetail(full_name, content_object)
def getDetails(self):
"""Get the details dict that will be reported with this test's outcome."""
if self.__details is None:
self.__details = {}
return self.__details
@classmethod
def setUpClass(cls):
# Determines if the TestCase is using IBMQ credentials.
cls.using_ibmq_credentials = False
cls.log = logging.getLogger(cls.__name__)
@staticmethod
def _get_resource_path(filename, path=Path.TEST):
"""Get the absolute path to a resource.

241
qiskit/test/runtest.py Normal file
View File

@ -0,0 +1,241 @@
# -*- coding: utf-8 -*-
# This code is part of Qiskit.
#
# (C) Copyright IBM 2017, 2018.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
# Copyright (c) 2009-2010 testtools developers.
# Forked from testing-cabal/testtools
# pylint: disable=missing-return-type-doc,missing-type-doc,missing-type-doc,invalid-name
# pylint: disable=broad-except,attribute-defined-outside-init,unused-argument
"""Individual test case execution."""
__all__ = [
'MultipleExceptions',
'RunTest',
]
import sys
from testtools.testresult import ExtendedToOriginalDecorator
class MultipleExceptions(Exception):
"""Represents many exceptions raised from some operation.
:ivar args: The sys.exc_info() tuples for each exception.
"""
class RunTest:
"""An object to run a test.
RunTest objects are used to implement the internal logic involved in
running a test. TestCase.__init__ stores _RunTest as the class of RunTest
to execute. Passing the runTest= parameter to TestCase.__init__ allows a
different RunTest class to be used to execute the test.
Subclassing or replacing RunTest can be useful to add functionality to the
way that tests are run in a given project.
:ivar case: The test case that is to be run.
:ivar result: The result object a case is reporting to.
:ivar handlers: A list of (ExceptionClass, handler_function) for
exceptions that should be caught if raised from the user
code. Exceptions that are caught are checked against this list in
first to last order. There is a catch-all of 'Exception' at the end
of the list, so to add a new exception to the list, insert it at the
front (which ensures that it will be checked before any existing base
classes in the list. If you add multiple exceptions some of which are
subclasses of each other, add the most specific exceptions last (so
they come before their parent classes in the list).
:ivar exception_caught: An object returned when _run_user catches an
exception.
:ivar _exceptions: A list of caught exceptions, used to do the single
reporting of error/failure/skip etc.
"""
def __init__(self, case, handlers=None, last_resort=None):
"""Create a RunTest to run a case.
Args:
case: A test case object.
handlers: Exception handlers for this RunTest. These are stored
in self.handlers and can be modified later if needed.
last_resort: A handler of last resort: any exception which is
not handled by handlers will cause the last resort handler to be
called as last_resort(exc_info), and then the exception will be
raised - aborting the test run as this is inside the runner
machinery rather than the confined context of the test.
"""
self.case = case
self.handlers = handlers or []
self.exception_caught = object()
self._exceptions = []
self.last_resort = last_resort or (lambda case, result, exc: None)
def run(self, result=None):
"""Run self.case reporting activity to result.
Args:
result: Optional testtools.TestResult to report activity to.
Returns:
The result object the test was run against.
"""
if result is None:
actual_result = self.case.defaultTestResult()
actual_result.startTestRun()
else:
actual_result = result
try:
return self._run_one(actual_result)
finally:
if result is None:
actual_result.stopTestRun()
def _run_one(self, result):
"""Run one test reporting to result.
:param result: A testtools.TestResult to report activity to.
This result object is decorated with an ExtendedToOriginalDecorator
to ensure that the latest TestResult API can be used with
confidence by client code.
:return: The result object the test was run against.
"""
return self._run_prepared_result(ExtendedToOriginalDecorator(result))
def _run_prepared_result(self, result):
"""Run one test reporting to result.
:param result: A testtools.TestResult to report activity to.
:return: The result object the test was run against.
"""
result.startTest(self.case)
self.result = result
try:
self._exceptions = []
self.case.__testtools_tb_locals__ = getattr(
result, 'tb_locals', False)
self._run_core()
if self._exceptions:
# One or more caught exceptions, now trigger the test's
# reporting method for just one.
e = self._exceptions.pop()
for exc_class, handler in self.handlers:
if isinstance(e, exc_class):
handler(self.case, self.result, e)
break
else:
self.last_resort(self.case, self.result, e)
raise e
finally:
result.stopTest(self.case)
return result
def _run_core(self):
"""Run the user supplied test code."""
test_method = self.case._get_test_method()
skip_case = getattr(self.case, '__unittest_skip__', False)
if skip_case or getattr(test_method, '__unittest_skip__', False):
self.result.addSkip(
self.case,
reason=getattr(self.case if skip_case else test_method,
'__unittest_skip_why__', None)
)
return
if self.exception_caught == self._run_user(self.case._run_setup,
self.result):
# Don't run the test method if we failed getting here.
self._run_cleanups(self.result)
return
# Run everything from here on in. If any of the methods raise an
# exception we'll have failed.
failed = False
try:
if self.exception_caught == self._run_user(
self.case._run_test_method, self.result):
failed = True
finally:
try:
if self.exception_caught == self._run_user(
self.case._run_teardown, self.result):
failed = True
finally:
try:
if self.exception_caught == self._run_user(
self._run_cleanups, self.result):
failed = True
finally:
if getattr(self.case, 'force_failure', None):
self._run_user(_raise_force_fail_error)
failed = True
if not failed:
self.result.addSuccess(self.case,
details=self.case.getDetails())
def _run_cleanups(self, result):
"""Run the cleanups that have been added with addCleanup.
See the docstring for addCleanup for more information.
:return: None if all cleanups ran without error,
``exception_caught`` if there was an error.
"""
failing = False
while self.case._cleanups:
function, arguments, keywordArguments = self.case._cleanups.pop()
got_exception = self._run_user(
function, *arguments, **keywordArguments)
if got_exception == self.exception_caught:
failing = True
if failing:
return self.exception_caught
def _run_user(self, fn, *args, **kwargs):
"""Run a user supplied function.
Exceptions are processed by `_got_user_exception`.
:return: Either whatever 'fn' returns or ``exception_caught`` if
'fn' raised an exception.
"""
try:
return fn(*args, **kwargs)
except Exception:
return self._got_user_exception(sys.exc_info())
def _got_user_exception(self, exc_info, tb_label='traceback'):
"""Called when user code raises an exception.
If 'exc_info' is a `MultipleExceptions`, then we recurse into it
unpacking the errors that it's made up from.
:param exc_info: A sys.exc_info() tuple for the user error.
:param tb_label: An optional string label for the error. If
not specified, will default to 'traceback'.
:return: 'exception_caught' if we catch one of the exceptions that
have handlers in 'handlers', otherwise raise the error.
"""
if exc_info[0] is MultipleExceptions:
for sub_exc_info in exc_info[1].args:
self._got_user_exception(sub_exc_info, tb_label)
return self.exception_caught
try:
e = exc_info[1]
self.case.onException(exc_info, tb_label=tb_label)
finally:
del exc_info
self._exceptions.append(e)
# Yes, this means we catch everything - we re-raise KeyBoardInterrupt
# etc later, after tearDown and cleanUp - since those may be cleaning up
# external processes.
return self.exception_caught
def _raise_force_fail_error():
raise AssertionError("Forced Test Failure")
# Signal that this is part of the testing framework, and that code from this
# should not normally appear in tracebacks.
__unittest = True

View File

@ -26,6 +26,7 @@ class TestBasicAerIntegration(QiskitTestCase):
"""Qiskit BasicAer simulator integration tests."""
def setUp(self):
super().setUp()
qr = QuantumRegister(1)
cr = ClassicalRegister(1)
self._qc1 = QuantumCircuit(qr, cr, name='qc1')

View File

@ -25,6 +25,7 @@ class LoadFromQasmTest(QiskitTestCase):
"""Test circuit.from_qasm_* set of methods."""
def setUp(self):
super().setUp()
self.qasm_file_name = 'entangled_registers.qasm'
self.qasm_file_path = self._get_resource_path('qasm/' + self.qasm_file_name, Path.EXAMPLES)

View File

@ -25,6 +25,7 @@ class TestCircuitCompose(QiskitTestCase):
"""Test composition of two circuits."""
def setUp(self):
super().setUp()
qreg1 = QuantumRegister(3, 'lqr_1')
qreg2 = QuantumRegister(2, 'lqr_2')
creg = ClassicalRegister(2, 'lcr')

View File

@ -1051,7 +1051,7 @@ class TestOpenControlledToMatrix(QiskitTestCase):
try:
actual = cgate.to_matrix()
except CircuitError as cerr:
self.skipTest(cerr)
self.skipTest(str(cerr))
self.assertTrue(np.allclose(actual, target))

View File

@ -29,6 +29,7 @@ class TestStandard1Q(QiskitTestCase):
"""Standard Extension Test. Gates with a single Qubit"""
def setUp(self):
super().setUp()
self.qr = QuantumRegister(3, "q")
self.qr2 = QuantumRegister(3, "r")
self.cr = ClassicalRegister(3, "c")
@ -953,6 +954,7 @@ class TestStandard2Q(QiskitTestCase):
"""Standard Extension Test. Gates with two Qubits"""
def setUp(self):
super().setUp()
self.qr = QuantumRegister(3, "q")
self.qr2 = QuantumRegister(3, "r")
self.cr = ClassicalRegister(3, "c")
@ -1300,6 +1302,7 @@ class TestStandard3Q(QiskitTestCase):
"""Standard Extension Test. Gates with three Qubits"""
def setUp(self):
super().setUp()
self.qr = QuantumRegister(3, "q")
self.qr2 = QuantumRegister(3, "r")
self.qr3 = QuantumRegister(3, "s")

View File

@ -32,10 +32,6 @@ from qiskit.transpiler.passes import CXCancellation
class TestUnitaryGate(QiskitTestCase):
"""Tests for the Unitary class."""
def setUp(self):
"""Setup."""
pass
def test_set_matrix(self):
"""Test instantiation"""
try:

View File

@ -50,6 +50,7 @@ class TestCircuitAssembler(QiskitTestCase):
"""Tests for assembling circuits to qobj."""
def setUp(self):
super().setUp()
qr = QuantumRegister(2, name='q')
cr = ClassicalRegister(2, name='c')
self.circ = QuantumCircuit(qr, cr, name='circ')
@ -460,6 +461,7 @@ class TestPulseAssembler(QiskitTestCase):
"""Tests for assembling schedules to qobj."""
def setUp(self):
super().setUp()
self.backend = FakeOpenPulse2Q()
self.backend_config = self.backend.configuration()
@ -1043,6 +1045,7 @@ class TestPulseAssemblerMissingKwargs(QiskitTestCase):
"""Verify that errors are raised in case backend is not provided and kwargs are missing."""
def setUp(self):
super().setUp()
self.schedule = pulse.Schedule(name='fake_experiment')
self.backend = FakeOpenPulse2Q()
@ -1219,6 +1222,7 @@ class TestLogAssembler(QiskitTestCase):
"""Testing the log_assembly option."""
def setUp(self):
super().setUp()
logger = getLogger()
logger.setLevel('DEBUG')
self.output = io.StringIO()

View File

@ -28,6 +28,7 @@ class TestCompiler(QiskitTestCase):
"""Qiskit Compiler Tests."""
def setUp(self):
super().setUp()
self.seed_simulator = 42
self.backend = BasicAer.get_backend("qasm_simulator")

View File

@ -216,6 +216,7 @@ class TestPulseScheduleDisassembler(QiskitTestCase):
"""Tests for disassembling pulse schedules to qobj."""
def setUp(self):
super().setUp()
self.backend = FakeOpenPulse2Q()
self.backend_config = self.backend.configuration()
self.backend_config.parametric_pulses = [

View File

@ -769,6 +769,7 @@ class TestLogTranspile(QiskitTestCase):
"""Testing the log_transpile option."""
def setUp(self):
super().setUp()
logger = getLogger()
logger.setLevel('DEBUG')
self.output = io.StringIO()

View File

@ -24,6 +24,7 @@ class TestAstToDag(QiskitTestCase):
"""Test AST to DAG."""
def setUp(self):
super().setUp()
qr = QuantumRegister(3)
cr = ClassicalRegister(3)
self.circuit = QuantumCircuit(qr, cr)

View File

@ -24,6 +24,7 @@ class TestDagCompose(QiskitTestCase):
"""Test composition of two dags"""
def setUp(self):
super().setUp()
qreg1 = QuantumRegister(3, 'lqr_1')
qreg2 = QuantumRegister(2, 'lqr_2')
creg = ClassicalRegister(2, 'lcr')

View File

@ -178,6 +178,7 @@ class TestDagApplyOperation(QiskitTestCase):
"""Test adding an op node to a dag."""
def setUp(self):
super().setUp()
self.dag = DAGCircuit()
qreg = QuantumRegister(3, 'qr')
creg = ClassicalRegister(2, 'cr')
@ -353,6 +354,7 @@ class TestDagNodeSelection(QiskitTestCase):
"""Test methods that select certain dag nodes"""
def setUp(self):
super().setUp()
self.dag = DAGCircuit()
qreg = QuantumRegister(3, 'qr')
creg = ClassicalRegister(2, 'cr')
@ -767,6 +769,58 @@ class TestDagLayers(QiskitTestCase):
self.assertEqual(comp, truth)
class TestCircuitProperties(QiskitTestCase):
"""DAGCircuit properties test."""
def setUp(self):
super().setUp()
qr1 = QuantumRegister(4)
qr2 = QuantumRegister(2)
circ = QuantumCircuit(qr1, qr2)
circ.h(qr1[0])
circ.cx(qr1[2], qr1[3])
circ.h(qr1[2])
circ.t(qr1[2])
circ.ch(qr1[2], qr1[1])
circ.u2(0.1, 0.2, qr1[3])
circ.ccx(qr2[0], qr2[1], qr1[0])
self.dag = circuit_to_dag(circ)
def test_circuit_size(self):
"""Test total number of operations in circuit."""
self.assertEqual(self.dag.size(), 7)
def test_circuit_depth(self):
"""Test circuit depth."""
self.assertEqual(self.dag.depth(), 4)
def test_circuit_width(self):
"""Test number of qubits + clbits in circuit."""
self.assertEqual(self.dag.width(), 6)
def test_circuit_num_qubits(self):
"""Test number of qubits in circuit."""
self.assertEqual(self.dag.num_qubits(), 6)
def test_circuit_operations(self):
"""Test circuit operations breakdown by kind of op."""
operations = {
'h': 2,
't': 1,
'u2': 1,
'cx': 1,
'ch': 1,
'ccx': 1
}
self.assertDictEqual(self.dag.count_ops(), operations)
def test_circuit_factors(self):
"""Test number of separable factors in circuit."""
self.assertEqual(self.dag.num_tensor_factors(), 2)
class TestCircuitSpecialCases(QiskitTestCase):
"""DAGCircuit test for special cases, usually for regression."""
@ -790,6 +844,7 @@ class TestDagEquivalence(QiskitTestCase):
"""DAGCircuit equivalence check."""
def setUp(self):
super().setUp()
self.qr1 = QuantumRegister(4, 'qr1')
self.qr2 = QuantumRegister(2, 'qr2')
circ1 = QuantumCircuit(self.qr2, self.qr1)
@ -855,6 +910,7 @@ class TestDagSubstitute(QiskitTestCase):
"""Test substituting a dag node with a sub-dag"""
def setUp(self):
super().setUp()
self.dag = DAGCircuit()
qreg = QuantumRegister(3, 'qr')
creg = ClassicalRegister(2, 'cr')
@ -1009,6 +1065,7 @@ class TestDagProperties(QiskitTestCase):
"""
def setUp(self):
super().setUp()
qr1 = QuantumRegister(4)
qr2 = QuantumRegister(2)
circ = QuantumCircuit(qr1, qr2)

View File

@ -102,6 +102,7 @@ class TestDagNodeEdge(QiskitTestCase):
"""Test adding nodes and edges to a dag and related functions."""
def setUp(self):
super().setUp()
self.dag = DAGDependency()
self.qreg = QuantumRegister(2, 'qr')
self.creg = ClassicalRegister(2, 'cr')
@ -164,6 +165,7 @@ class TestDagNodeSelection(QiskitTestCase):
"""Test methods that select successors and predecessors"""
def setUp(self):
super().setUp()
self.dag = DAGDependency()
self.qreg = QuantumRegister(2, 'qr')
self.creg = ClassicalRegister(2, 'cr')
@ -213,6 +215,7 @@ class TestDagProperties(QiskitTestCase):
"""
def setUp(self):
super().setUp()
qr1 = QuantumRegister(4)
qr2 = QuantumRegister(2)
circ = QuantumCircuit(qr1, qr2)

View File

@ -26,6 +26,7 @@ class TestBackendConfiguration(QiskitTestCase):
"""Test the methods on the BackendConfiguration class."""
def setUp(self):
super().setUp()
self.provider = FakeProvider()
self.config = self.provider.get_backend('fake_openpulse_2q').configuration()

View File

@ -27,6 +27,7 @@ class BackendpropertiesTestCase(QiskitTestCase):
backend_name = 'fake_ourense'
def setUp(self):
super().setUp()
self.provider = FakeProvider()
self.backend = self.provider.get_backend('fake_ourense')
self.properties = self.backend.properties()

View File

@ -22,6 +22,7 @@ class TestBaseBackend(QiskitTestCase):
"""Test the backend methods."""
def setUp(self):
super().setUp()
self.pulse_backend = FakeOpenPulse2Q()
self.backend = FakeMelbourne()

View File

@ -26,6 +26,7 @@ class TestPulseDefaults(QiskitTestCase):
"""Test the PulseDefaults creation and method usage."""
def setUp(self):
super().setUp()
self.defs = FakeOpenPulse2Q().defaults()
self.inst_map = self.defs.instruction_schedule_map

View File

@ -31,6 +31,7 @@ class TestBuilder(QiskitTestCase):
"""Test the pulse builder context."""
def setUp(self):
super().setUp()
self.backend = FakeOpenPulse2Q()
self.configuration = self.backend.configuration()
self.defaults = self.backend.defaults()

View File

@ -32,6 +32,7 @@ class TestMeasure(QiskitTestCase):
"""Pulse measure macro."""
def setUp(self):
super().setUp()
self.backend = FakeOpenPulse2Q()
self.inst_map = self.backend.defaults().instruction_schedule_map
@ -103,6 +104,7 @@ class TestMeasureAll(QiskitTestCase):
"""Pulse measure all macro."""
def setUp(self):
super().setUp()
self.backend = FakeOpenPulse2Q()
self.inst_map = self.backend.defaults().instruction_schedule_map

View File

@ -52,6 +52,8 @@ class BaseTestSchedule(QiskitTestCase):
"""Schedule tests."""
def setUp(self):
super().setUp()
@functional_pulse
def linear(duration, slope, intercept):
x = np.linspace(0, duration - 1, duration)

View File

@ -41,6 +41,7 @@ class TestAlignMeasures(QiskitTestCase):
"""Test the helper function which aligns acquires."""
def setUp(self):
super().setUp()
self.backend = FakeOpenPulse2Q()
self.config = self.backend.configuration()
self.inst_map = self.backend.defaults().instruction_schedule_map
@ -198,6 +199,7 @@ class TestAddImplicitAcquires(QiskitTestCase):
"""Test the helper function which makes implicit acquires explicit."""
def setUp(self):
super().setUp()
self.backend = FakeOpenPulse2Q()
self.config = self.backend.configuration()
self.short_pulse = pulse.Waveform(samples=np.array([0.02739068], dtype=np.complex128),

View File

@ -189,6 +189,7 @@ class TestQobjToInstructionConverter(QiskitTestCase):
"""Pulse converter tests."""
def setUp(self):
super().setUp()
self.linear = Waveform(np.arange(0, 0.01), name='linear')
self.pulse_library = [PulseLibraryItem(name=self.linear.name,
samples=self.linear.samples.tolist())]

View File

@ -39,6 +39,7 @@ class TestQASMQobj(QiskitTestCase):
"""Tests for QasmQobj."""
def setUp(self):
super().setUp()
self.valid_qobj = QasmQobj(
qobj_id='12345',
header=QobjHeader(),
@ -252,6 +253,7 @@ class TestPulseQobj(QiskitTestCase):
"""Tests for PulseQobj."""
def setUp(self):
super().setUp()
self.valid_qobj = PulseQobj(
qobj_id='12345',
header=QobjHeader(),

View File

@ -25,6 +25,7 @@ class TestQobjIdentifiers(QiskitTestCase):
"""Check the Qobj compiled for different backends create names properly"""
def setUp(self):
super().setUp()
qr = QuantumRegister(2, name="qr2")
cr = ClassicalRegister(2, name=None)
qc = QuantumCircuit(qr, cr, name="qc10")

View File

@ -66,6 +66,7 @@ class TestPauli(QiskitTestCase):
def setUp(self):
"""Setup."""
super().setUp()
z = np.asarray([1, 0, 1, 0]).astype(np.bool)
x = np.asarray([1, 1, 0, 0]).astype(np.bool)
self.ref_p = Pauli(z, x)

View File

@ -27,6 +27,7 @@ class TestQuaternions(QiskitTestCase):
"""Tests qiskit.quantum_info.operators.quaternion"""
def setUp(self):
super().setUp()
self.rnd_array = np.array([0.5, 0.8, 0.9, -0.3])
self.quat_unnormalized = Quaternion(self.rnd_array)
axes = ['x', 'y', 'z']

View File

@ -27,6 +27,7 @@ class TestBasicSchedule(QiskitTestCase):
"""Scheduling tests."""
def setUp(self):
super().setUp()
self.backend = FakeOpenPulse2Q()
self.inst_map = self.backend.defaults().instruction_schedule_map

View File

@ -34,6 +34,7 @@ class TestParser(QiskitTestCase):
"""QasmParser"""
def setUp(self):
super().setUp()
self.qasm_file_path = self._get_resource_path('example.qasm', Path.QASMS)
self.qasm_file_path_fail = self._get_resource_path(
'example_fail.qasm', Path.QASMS)

View File

@ -56,6 +56,7 @@ class TestSchemaExamples(QiskitTestCase):
}
def setUp(self):
super().setUp()
self.examples_base_path = self._get_resource_path('examples',
Path.SCHEMAS)

View File

@ -33,6 +33,7 @@ JUPYTER_KERNEL = 'python3'
class TestJupyter(QiskitTestCase):
"""Notebooks test case."""
def setUp(self):
super().setUp()
self.execution_path = os.path.join(Path.SDK.value, '..')
def _execute_notebook(self, filename):

View File

@ -26,6 +26,7 @@ class TestCommutationAnalysis(QiskitTestCase):
"""Test the Commutation pass."""
def setUp(self):
super().setUp()
self.pass_ = CommutationAnalysis()
self.pset = self.pass_.property_set = PropertySet()

View File

@ -26,7 +26,7 @@ class TestCommutativeCancellation(QiskitTestCase):
"""Test the CommutativeCancellation pass."""
def setUp(self):
super().setUp()
self.com_pass_ = CommutationAnalysis()
self.pass_ = CommutativeCancellation()
self.pset = self.pass_.property_set = PropertySet()

View File

@ -26,6 +26,7 @@ class TestDenseLayout(QiskitTestCase):
"""Tests the DenseLayout pass"""
def setUp(self):
super().setUp()
self.cmap20 = FakeTokyo().configuration().coupling_map
def test_5q_circuit_20q_coupling(self):

View File

@ -25,6 +25,7 @@ class TestEnlargeWithAncilla(QiskitTestCase):
"""Tests the EnlargeWithAncilla pass."""
def setUp(self):
super().setUp()
self.qr3 = QuantumRegister(3, 'qr')
circuit = QuantumCircuit(self.qr3)
circuit.h(self.qr3)

View File

@ -253,6 +253,7 @@ class TestFaultyQ1Unpickable(TestFaultyBackendCase):
def setUp(self):
"""Creates a FakeBackend that is unpickable"""
super().setUp()
backend = FakeOurenseFaultyQ1()
backend.unpickable_prop = (lambda x: x)
self.unpickable_backend = backend

View File

@ -21,6 +21,7 @@ class TestFixedPointPass(QiskitTestCase):
""" Tests for FixedPoint pass. """
def setUp(self):
super().setUp()
self.pass_ = FixedPoint('property')
self.pset = self.pass_.property_set
self.dag = None # The pass do not read the DAG.

View File

@ -25,6 +25,7 @@ class TestFullAncillaAllocation(QiskitTestCase):
"""Tests the ExtendLayout pass"""
def setUp(self):
super().setUp()
self.cmap5 = CouplingMap([[1, 0], [2, 0], [2, 1], [3, 2], [3, 4], [4, 2]])
def test_3q_circuit_5q_coupling(self):

View File

@ -26,6 +26,7 @@ class LayoutTest(QiskitTestCase):
"""Test the methods in the layout object."""
def setUp(self):
super().setUp()
self.qr = QuantumRegister(3, 'qr')
def test_default_layout(self):

View File

@ -24,6 +24,7 @@ class TestNamingTranspiledCircuits(QiskitTestCase):
"""Testing the naming fuctionality for transpiled circuits."""
def setUp(self):
super().setUp()
self.basis_gates = ['u1', 'u2', 'u3', 'cx']
self.backend = BasicAer.get_backend('qasm_simulator')

View File

@ -91,6 +91,7 @@ class TestUseCases(SchedulerTestCase):
in the right order."""
def setUp(self):
super().setUp()
self.circuit = QuantumCircuit(QuantumRegister(1))
self.passmanager = PassManager()
@ -422,6 +423,7 @@ class TestControlFlowPlugin(SchedulerTestCase):
"""Testing the control flow plugin system."""
def setUp(self):
super().setUp()
self.passmanager = PassManager()
self.circuit = QuantumCircuit(QuantumRegister(1))
@ -539,6 +541,7 @@ class TestLogPasses(QiskitTestCase):
"""Testing the log_passes option."""
def setUp(self):
super().setUp()
logger = getLogger()
logger.setLevel('DEBUG')
self.output = io.StringIO()
@ -612,6 +615,7 @@ class TestPassManagerReuse(SchedulerTestCase):
"""The PassManager instance should be reusable."""
def setUp(self):
super().setUp()
self.passmanager = PassManager()
self.circuit = QuantumCircuit(QuantumRegister(1))
@ -699,6 +703,7 @@ class TestPassManagerChanges(SchedulerTestCase):
"""Test PassManager manipulation with changes"""
def setUp(self):
super().setUp()
self.passmanager = PassManager()
self.circuit = QuantumCircuit(QuantumRegister(1))
@ -791,6 +796,7 @@ class TestPassManagerSlicing(SchedulerTestCase):
"""test PassManager slicing."""
def setUp(self):
super().setUp()
self.passmanager = PassManager()
self.circuit = QuantumCircuit(QuantumRegister(1))
@ -919,6 +925,7 @@ class TestPassManagerConcatenation(SchedulerTestCase):
"""test PassManager concatenation by + operator."""
def setUp(self):
super().setUp()
self.passmanager1 = PassManager()
self.passmanager2 = PassManager()
self.circuit = QuantumCircuit(QuantumRegister(1))

View File

@ -107,6 +107,7 @@ class TestPassesInspection(QiskitTestCase):
def setUp(self):
"""Sets self.callback to set self.passes with the passes that have been executed"""
super().setUp()
self.passes = []
def callback(**kwargs):

View File

@ -21,6 +21,7 @@ class TestPropertySet(QiskitTestCase):
""" Tests for PropertySet methods. """
def setUp(self):
super().setUp()
self.pset = PropertySet()
def test_get_non_existent(self):

View File

@ -26,6 +26,7 @@ class TestSabreLayout(QiskitTestCase):
"""Tests the SabreLayout pass"""
def setUp(self):
super().setUp()
self.cmap20 = FakeAlmaden().configuration().coupling_map
def test_5q_circuit_20q_coupling(self):

View File

@ -41,6 +41,7 @@ class TestGeneral(QiskitTestCase):
def setUp(self) -> None:
"""Set up test cases."""
super().setUp()
random.seed(0)
def test_simple(self) -> None:

View File

@ -27,6 +27,7 @@ class TestTrivialLayout(QiskitTestCase):
"""Tests the TrivialLayout pass"""
def setUp(self):
super().setUp()
self.cmap5 = FakeTenerife().configuration().coupling_map
self.cmap16 = FakeRueschlikon().configuration().coupling_map

View File

@ -216,6 +216,7 @@ class TestUnrollAllInstructions(QiskitTestCase):
"""Test unrolling a circuit containing all standard instructions."""
def setUp(self):
super().setUp()
qr = self.qr = QuantumRegister(3, 'qr')
cr = self.cr = ClassicalRegister(3, 'cr')
self.circuit = QuantumCircuit(qr, cr)

View File

@ -28,6 +28,7 @@ class TestGenerators(QiskitTestCase):
"""Tests for generators."""
def setUp(self) -> None:
super().setUp()
self.style = stylesheet.QiskitPulseStyle()
@staticmethod

View File

@ -2960,6 +2960,7 @@ class TestTextInitialValue(QiskitTestCase):
"""Testing the initial_state parameter"""
def setUp(self) -> None:
super().setUp()
qr = QuantumRegister(2, 'q')
cr = ClassicalRegister(2, 'c')
self.circuit = QuantumCircuit(qr, cr)

View File

@ -25,6 +25,7 @@ class TestDagDrawer(QiskitTestCase):
"""Qiskit DAG drawer tests."""
def setUp(self):
super().setUp()
qr = QuantumRegister(2, 'qr')
circuit = QuantumCircuit(qr)
circuit.cx(qr[0], qr[1])

View File

@ -70,6 +70,7 @@ class TestGraphDist(QiskitTestCase):
def setUp(self):
""" setup plots for _GraphDist """
super().setUp()
ax1 = plt.subplots(figsize=(5, 5))[1]
ax2 = plt.subplots(figsize=(9, 3))[1]
ax1.axis("off")

View File

@ -50,6 +50,7 @@ class TestPassManagerDrawer(QiskitVisualizationTestCase):
"""Qiskit pass manager drawer tests."""
def setUp(self):
super().setUp()
coupling = [[0, 1], [1, 2], [2, 3], [3, 4], [4, 5], [5, 6]]
coupling_map = CouplingMap(couplinglist=coupling)
basis_gates = ['u1', 'u3', 'u2', 'cx']

View File

@ -158,6 +158,7 @@ class TestVisualizationUtils(QiskitTestCase):
the need to be check if the interface or their result changes."""
def setUp(self):
super().setUp()
self.qr1 = QuantumRegister(2, 'qr1')
self.qr2 = QuantumRegister(2, 'qr2')
self.cr1 = ClassicalRegister(2, 'cr1')

View File

@ -12,6 +12,7 @@ setenv =
LC_ALL=en_US.utf-8
ARGS="-V"
QISKIT_SUPRESS_PACKAGING_WARNINGS=Y
QISKIT_TEST_CAPTURE_STREAMS=1
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/requirements-dev.txt
commands =