unittest: make obj work more like Function/Class#12089
unittest: make obj work more like Function/Class#12089bluetech merged 1 commit intopytest-dev:mainfrom
obj work more like Function/Class#12089Conversation
|
Did this while looking into #12065. Tested on some of my own (quite large) unittest+pytest projects, and also pytest-django which uses unittest internally (this required adding a backward compat property, but I will update pytest-django if this merged and we could remove the compat). |
nicoddemus
left a comment
There was a problem hiding this comment.
Looks great, thanks!
Left minor comments.
src/_pytest/unittest.py
Outdated
| # runTest is a special no-op name for unittest, can be used when a dummy | ||
| # instance is needed. |
There was a problem hiding this comment.
I don't quite get this comment... "name for unittest" you mean pytest's unittest, or stdlib unittest? Also is this recommending calling runTest to obtain a new dummy instance?
There was a problem hiding this comment.
I will update the comment to make it clearer. Also we don't really need the parameter so I'll omit it.
src/_pytest/unittest.py
Outdated
| # to declare that our children do not support funcargs. | ||
| nofuncargs = True | ||
|
|
||
| def newinstance(self, method_name: str = "runTest"): |
There was a problem hiding this comment.
I understand we have been using _ to separate words in new methods/functions? Anyway this is murky waters anyway, perhaps you wanted to keep consistency within this class.
There was a problem hiding this comment.
This overrides Class.newinstance so needs the same name
| for obj in gc.get_objects(): | ||
| assert type(obj).__name__ != "TestCaseObjectsShouldBeCleanedUp" | ||
| if type(obj).__name__ == "TestCaseObjectsShouldBeCleanedUp": | ||
| assert not hasattr(obj, "an_expensive_obj") |
There was a problem hiding this comment.
Where does this an_expensive_obj comes from? Perhaps leaving a comment explaining it.
There was a problem hiding this comment.
I think it's maybe clearer when reading the entire test?
Previously, the `obj` of a `TestCaseFunction` (the unittest plugin item type) was the unbound method. This is unlike regular `Class` where the `obj` is a bound method to a fresh instance. This difference necessitated several special cases in in places outside of the unittest plugin, such as `FixtureDef` and `FixtureRequest`, and made things a bit harder to understand. Instead, match how the python plugin does it, including collecting fixtures from a fresh instance. The downside is that now this instance for fixture-collection is kept around in memory, but it's the same as `Class` so nothing new. Users should only initialize stuff in `setUp`/`setUpClass` and similar methods, and not in `__init__` which is generally off-limits in `TestCase` subclasses. I am not sure why there was a difference in the first place, though I will say the previous unittest approach is probably the preferable one, but first let's get consistency.
|
Fully understand this change, but this should really have be listed as a breaking change - upgrading pytest caused me to have to track down why collection was failing, and took me a good amount of debugging to find this. |
--- In pytest >=8.2.0 the unittest logic has been reworked to work more like a Function/Class, (see pytest-dev/pytest/pull/12089). This has the side-effect that during the collection phase all test are instantiated and given that the __init__ func of TraceTestCase includes required keyword arguments not being fulfilled in the collection phase it errors. This is avoided by setting default values on the __init__ definition so a `TraceTestCase.__init__() ` run during collection phase won't error. pytest changelog: https://docs.pytest.org/en/stable/changelog.html#pytest-8-2-0-2024-04-27
--- In pytest >=8.2.0 the unittest logic has been reworked to work more like a Function/Class, (see pytest-dev/pytest/pull/12089). This has the side-effect that during the collection phase all test are instantiated and given that the __init__ func of TraceTestCase includes required keyword arguments not being fulfilled in the collection phase it errors. This is avoided by setting default values on the __init__ definition so a `TraceTestCase.__init__() ` run during collection phase won't error. pytest changelog: https://docs.pytest.org/en/stable/changelog.html#pytest-8-2-0-2024-04-27 Signed-off-by: claraberendsen <42071084+claraberendsen@users.noreply.github.com>
…#236) * set default values to avoid errors during collection phase --- In pytest >=8.2.0 the unittest logic has been reworked to work more like a Function/Class, (see pytest-dev/pytest/pull/12089). This has the side-effect that during the collection phase all test are instantiated and given that the __init__ func of TraceTestCase includes required keyword arguments not being fulfilled in the collection phase it errors. This is avoided by setting default values on the __init__ definition so a `TraceTestCase.__init__() ` run during collection phase won't error. pytest changelog: https://docs.pytest.org/en/stable/changelog.html#pytest-8-2-0-2024-04-27 Signed-off-by: claraberendsen <42071084+claraberendsen@users.noreply.github.com> * fix flake8 errors Signed-off-by: claraberendsen <42071084+claraberendsen@users.noreply.github.com> * use single quotes to please flake8 Signed-off-by: claraberendsen <42071084+claraberendsen@users.noreply.github.com> * Use None as default instead of Lists Co-authored-by: Christophe Bedard <bedard.christophe@gmail.com> Signed-off-by: Clara Berendsen <42071084+claraberendsen@users.noreply.github.com> * Manage optional parameters on instantiation Signed-off-by: claraberendsen <42071084+claraberendsen@users.noreply.github.com> --------- Signed-off-by: claraberendsen <42071084+claraberendsen@users.noreply.github.com> Signed-off-by: Clara Berendsen <42071084+claraberendsen@users.noreply.github.com> Co-authored-by: Christophe Bedard <bedard.christophe@gmail.com>
…ros2#236) * set default values to avoid errors during collection phase --- In pytest >=8.2.0 the unittest logic has been reworked to work more like a Function/Class, (see pytest-dev/pytest/pull/12089). This has the side-effect that during the collection phase all test are instantiated and given that the __init__ func of TraceTestCase includes required keyword arguments not being fulfilled in the collection phase it errors. This is avoided by setting default values on the __init__ definition so a `TraceTestCase.__init__() ` run during collection phase won't error. pytest changelog: https://docs.pytest.org/en/stable/changelog.html#pytest-8-2-0-2024-04-27 Signed-off-by: claraberendsen <42071084+claraberendsen@users.noreply.github.com> * fix flake8 errors Signed-off-by: claraberendsen <42071084+claraberendsen@users.noreply.github.com> * use single quotes to please flake8 Signed-off-by: claraberendsen <42071084+claraberendsen@users.noreply.github.com> * Use None as default instead of Lists Co-authored-by: Christophe Bedard <bedard.christophe@gmail.com> Signed-off-by: Clara Berendsen <42071084+claraberendsen@users.noreply.github.com> * Manage optional parameters on instantiation Signed-off-by: claraberendsen <42071084+claraberendsen@users.noreply.github.com> --------- Signed-off-by: claraberendsen <42071084+claraberendsen@users.noreply.github.com> Signed-off-by: Clara Berendsen <42071084+claraberendsen@users.noreply.github.com> Co-authored-by: Christophe Bedard <bedard.christophe@gmail.com>
Previously, the
objof aTestCaseFunction(the unittest plugin item type) was the unbound method. This is unlike regularClasswhere theobjis a bound method to a fresh instance.This difference necessitated several special cases in in places outside of the unittest plugin, such as
FixtureDefandFixtureRequest, and made things a bit harder to understand.Instead, match how the python plugin does it, including collecting fixtures from a fresh instance.
The downside is that now this instance for fixture-collection is kept around in memory, but it's the same as
Classso nothing new. Users should only initialize stuff insetUp/setUpClassand similar methods, and not in__init__which is generally off-limits inTestCasesubclasses.I am not sure why there was a difference in the first place, though I will say the previous unittest approach is probably the preferable one, but first let's get consistency.