Consider replacing pytest in functional2 #594
Labels
No labels
Affects/CppNix
Affects/Nightly
Affects/Only nightly
Affects/Stable
Area/build-packaging
Area/cli
Area/evaluator
Area/fetching
Area/flakes
Area/language
Area/lix ci
Area/nix-eval-jobs
Area/profiles
Area/protocol
Area/releng
Area/remote-builds
Area/repl
Area/repl/debugger
Area/store
bug
Context
contributors
Context
drive-by
Context
maintainers
Context
RFD
crash 💥
Cross Compilation
devx
docs
Downstream Dependents
E/easy
E/hard
E/help wanted
E/reproducible
E/requires rearchitecture
imported
Language/Bash
Language/C++
Language/NixLang
Language/Python
Language/Rust
Needs Langver
OS/Linux
OS/macOS
performance
regression
release-blocker
stability
Status
blocked
Status
invalid
Status
postponed
Status
wontfix
testing
testing/flakey
Topic/Large Scale Installations
ux
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lix-project/lix#594
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
I am getting bad vibes from pytest to be honest, especially with #593. Among other things, it could be a lot faster, particularly startup-time wise, and I am mildly worried that we might want to have the ability to do threading or asyncio driven parallelism in the future for faster testing which it entirely cannot do. The startup times at present are not great and spawning a pile of workers is a super bad design for something which does not have the normal python reason for being slow or the normal python reasons to need a process-pool solution.
It also does a lot of magic, such as automatically loading plugins based on PYTHONPATH (proximate cause of #593). I also don't really like the way that the fixtures interact with type annotations. I would rather the fixtures be defined by the type annotations, which makes it significantly more obvious what they are and improves IDE behaviour substantially. Overall it is extremely complex and this complexity seems to be causing some hauntings.
Maybe we should replace it with something like chromium's expect_tests or @puck's nix conformance suite runner or something written from scratch.
This is not to say that functional2 should not be used; there is no urgency to actually execute on a replacement since the test-facing interface is both good and fairly abstract, and we can just migrate the code if we decide we want something different. It's more important that we have decent tests at the moment IMO.
Does anyone have any thoughts or opinions on this? We are in no rush to actually make any changes here.
@cobaltcause on matrix:
i::jade concur with this and it is a major beef i have with pytest. in practice the fixtures exist primarily to avoid context manager rightward drift, which could be replaced with a thing for combining multiple context managers. it also exists to deal with having shared per-test temp directory or so flexibly (which is fair enough). basically a test has to be able to set shared things in its context which can reuse the memoized versions of other things in the context and this is inevitably going to be somewhat ugly even if you force explicit data passing.
but with statements can totally instantiate multiple context managers from a simple list of them as though they were nested? if fixtures are mainly around to turn
with foo() as a, bar() as b:
intodef nonsense(foo, bar):
, then what even is the point? (confused noises)So they both manage life cycle and also allow sharing fixtures between tests (and between fixtures in one test). The latter reason is an important one that it would be nice to still be able to have fixtures somehow: being able to ask the ambient environment what the temp dir is for the test without having to explicitly give it is a very nice thing as it avoids having to change a pile of call sites if you need another bit of such state for a fixture. It's the classical dependency injection framework thing.
However, we could implement this differently: tests could be given a TestContext from which you can
with ctx.fixture(Nix) as nix, ctx.fixture(BinaryCacheServer) as bcs
. Or do that to fixtures. There could be some amount of explicitness to remove the worst of the magic.Well, that's the point! Unlike the
with
statement, functions are composable in Python: you can take them as arguments to functions and pass them as arguments to other functions. This lets you do Dependency Injection and have tests and fixtures depend on fixtures that are only defined in one place.Also, personally, I've always struggled writing code that is needed to use
with
in Python; I assume that's especially true for people who had less experience with static typing languages that have interfaces and stuff. But that's less of a technical and more of a, uhh, cultural issue I guess :)I saw mentions of Rust in Matrix, so I just had to chime in and put my own 2 cents here. So here goes.
Regarding pytest: yeah, aside from turning
with foo() as a
intodef nonsense(a)
, it also does a whole bunch of ad-hoc things related to state management which I just don't love.For the Rust side, it's weird. Rust has a lot of cool testing libraries for snapshot testing, regression testing, property testing and all kinds of other weird things, but from what I've seen testing in Rust often tends to fall into one of: a lot of repetition, homegrown approaches, or macro abuse.
So I guess I'm in favor of rewriting the Python test runner. I'd rather a homegrown test runner than a homegrown Rust test suite.