Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BasicQiskitTestCase and FullQiskitTestCase do not enforce call behaviour consistently #6746

Closed
jakelishman opened this issue Jul 14, 2021 · 1 comment · Fixed by #6753
Closed
Assignees
Labels
bug Something isn't working
Milestone

Comments

@jakelishman
Copy link
Member

jakelishman commented Jul 14, 2021

Information

  • Qiskit Terra version: 0.19.dev
  • Python version: all
  • Operating system: all

What is the current behavior?

The main QiskitTestClass is bound to either BasicQiskitTestClass or FullQiskitTestClass, depending on whether fixtures and testtools are available, and if the QISKIT_TEST_CAPTURE_STREAMS environment variable is set. These two classes have differences in enforcement of certain behaviours, meaning that when running local tests without setting the envvar, you may see spurious passes in new tests. If you use tox to run the tests locally, it should always arrange the setup such that FullQiskitTestCase gets used (like in the CI), but if you're just doing quick-and-dirty tests with python -munittest or stestr, you might get BasicQiskitTestCase.

In particular, the Full setUp and tearDown methods require subclasses to explicitly call super().setUp() (and similar), and the Full class silences a lot of deprecation warnings which Basic doesn't.

Steps to reproduce the problem

Test file mytest.py

from qiskit.test import QiskitTestCase

class MyTest(QiskitTestCase):
    def setUp(self) -> None:
        pass
    def test_something(self):
        pass

Now, assuming testtools is available

$ # Disable stream capture => BasicQiskitTestCase
$ QISKIT_TEST_CAPTURE_STREAMS= python -munittest mytest.py
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
$ # Enable stream capture => FullQiskitTestCase
$ QISKIT_TEST_CAPTURE_STREAMS=1 python -munittest mytest.py
E
======================================================================
ERROR: test_something (mytest.myTest)
----------------------------------------------------------------------
testtools.testresult.real._StringException: Traceback (most recent call last):
ValueError: In File: /Users/jake/tmp/mytest.py
TestCase.setUp was not called. Have you upcalled all the way up the hierarchy from your setUp? e.g. Call super(myTest, self).setUp() from your setUp().


----------------------------------------------------------------------
Ran 1 test in 0.003s

FAILED (errors=1)

What is the expected behavior?

Both should throw the same error.

Suggested solutions

Only functionality which entirely depends on the presence of testtools should be different between the two classes. A lot of extra functionality (deprecation warnings, etc) could be moved into BaseQiskitTestCase and shared.

@jakelishman jakelishman added the bug Something isn't working label Jul 14, 2021
@jakelishman
Copy link
Member Author

jakelishman added a commit to jakelishman/qiskit-terra that referenced this issue Jul 15, 2021
The previous split was to avoid having testtools as a core testing
dependency, even though it was present in all CI tests.  This eventually
led to more fracturing of the two classes, where various extra
functionality was added into FullQiskitTestCase, but not into
BasicQiskitTestCase (see Qiskit#6746).  This meant downstream consumers of
QiskitTestCase sometimes had to care about how Terra's tests were
configured (see Qiskit/qiskit-aer#1283), and running simple local tests
without setting the environment variable QISKIT_TEST_CAPTURE_STREAMS
would run with different configurations.

This unifies the two classes, such that QiskitTestCase is now the parent
class of FullQiskitTestCase.  All non-testtools/non-fixtures related
additions are handled in QiskitTestCase, and FullQiskitTestCase adds on
the testtools-specific functionality.  FullQiskitTestCase is still not
made a subclass of testtools.TestClass because the same issues mentioned
in Qiskit#3982 are still present in testtools.

Whether to capture streams and whether to use the testtools machinery
are two separate concerns, with the availability of the former being
strictly dependent on the latter.  We can bind to the "full"
testtools-based class provided testtools is available, and it internally
decides whether it should also add the stream-capturing mechanisms.

The shared functionality added to the setUp, setUpClass and tearDown
methods means that it is important all subclasses always call up the
stack with super().  testtools has always enforced this using custom
_run_setup() methods, but this is not available to us when it is not
being used as the runner.  Instead, the parent class is modified after
creation, wrapping certain methods with additional checks, and the
__init_subclass__ method is used to influence the creation of children,
to add similar tests when they are created.
@mergify mergify bot closed this as completed in #6753 Aug 3, 2021
mergify bot pushed a commit that referenced this issue Aug 3, 2021
* Unify setup and teardown methods of TestCases

The previous split was to avoid having testtools as a core testing
dependency, even though it was present in all CI tests.  This eventually
led to more fracturing of the two classes, where various extra
functionality was added into FullQiskitTestCase, but not into
BasicQiskitTestCase (see #6746).  This meant downstream consumers of
QiskitTestCase sometimes had to care about how Terra's tests were
configured (see Qiskit/qiskit-aer#1283), and running simple local tests
without setting the environment variable QISKIT_TEST_CAPTURE_STREAMS
would run with different configurations.

This unifies the two classes, such that QiskitTestCase is now the parent
class of FullQiskitTestCase.  All non-testtools/non-fixtures related
additions are handled in QiskitTestCase, and FullQiskitTestCase adds on
the testtools-specific functionality.  FullQiskitTestCase is still not
made a subclass of testtools.TestClass because the same issues mentioned
in #3982 are still present in testtools.

Whether to capture streams and whether to use the testtools machinery
are two separate concerns, with the availability of the former being
strictly dependent on the latter.  We can bind to the "full"
testtools-based class provided testtools is available, and it internally
decides whether it should also add the stream-capturing mechanisms.

The shared functionality added to the setUp, setUpClass and tearDown
methods means that it is important all subclasses always call up the
stack with super().  testtools has always enforced this using custom
_run_setup() methods, but this is not available to us when it is not
being used as the runner.  Instead, the parent class is modified after
creation, wrapping certain methods with additional checks, and the
__init_subclass__ method is used to influence the creation of children,
to add similar tests when they are created.

* Explicitly mark unused arguments

The decorator's internal functions take arguments *args and **kwargs,
in order to wrap arbitrary functions, but pylint complains about them
not being used.  The arguments are explicitly meant to be ignored, which
in pylint-speak means prepending with an underscore.

* Retain the BaseQiskitTestCase class

The previous commit removed this base class without issuing any
deprecation warnings.  That's clearly wrong.  Further, we actually want
to properly formalise a separation between a completely public
test-additions API, for _all_ Qiskit-family packages to use, and
additions which are specific to Terra.  `assertDictsAreEqual` is an
example of the former, but logging and warning control are examples of
the latter.

Deciding on a complete split is out-of-scope for this PR, but this
commit reinstates the previous names, to avoid breaking downstream code.

* Convert docstrings to googledoc format
@kdk kdk added this to the 0.19 milestone Nov 15, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants