-
Notifications
You must be signed in to change notification settings - Fork 26
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
Investigate how we might get rid of the Quick testing framework #1201
Comments
A progress update, and some further thoughts. What I've doneI've put together a prototype using SwiftSyntax, which is capable of:
Neither of these are hugely complicated things but they've given me confidence in how to use SwiftSyntax to interrogate the contents of a method and extract things like calls to Viability of the approachI believe that we will be able to extend this prototype to handle the (more complicated) nested test cases. This is where having access to the AST will truly show its utility over a simple find-and-replace. Potential complications for automationWe have some (I don't know how many) dynamically-defined tests — for example, Considerations for landing this changeWe need to make sure that these changes are reviewable by a human being. That means we need to be able to view a diff that shows only the structural changes to the tests (we can't expect anyone to review our ~25,000 lines of test code, and even less so expect them to compare two different sets of 25,000 lines of code to make sure most of it hasn't changed by accident). That means that we'll probably need to preserve the current indentation levels of the tests, even though syntactically we're completely flattening the structure (since all of the generated Other logistical considerations
Decisions to make
|
I think the next steps, if we're happy to continue down the automation route, are to build out the prototype to handle nesting. |
A status update. Once I finished the first version of the migrator, the migrated code had three new test failures. Long story short, I've spent a fair chunk of time investigating these, operating under the assumption that they must result from the behaviour of the migrated code differing from that of the Quick code. I believe I've now got the migrator emitting code that behaves almost identically to the original Quick code, and I'm happy to say this appears to have resolved the failures. I'm now going to start landing some of this work into |
The existing implementation used a loop to implement a form of table-based testing (i.e. define a list of tests at runtime). Here I remove this loop, extracting its body to a function (whose name begins with `reusableTests`) and replacing the iteration with a static list of invocations fo this function. The motivation for this change is that it’s groundwork for removing the Quick testing framework using an automated migrator tool (#1201). The migrator that I’m writing only knows how to handle a specific set of statements at a `context`/`describe` level, and would not know what to do with e.g. an expression like a `forEach` call. (It wouldn’t be able solve this problem generally without executing the test code during the migration.) Hence we replace these expressions with something that the migrator knows how to handle. The `reusableTests` prefix is important here — the migrator _does_ know how handle a call to this kind of function and knows that, unlike other function declarations, it should look inside the body of this function, where it will find more tests that it needs to migrate.
The motivation for this change is that it’s groundwork for removing the Quick testing framework using an automated migrator tool (#1201). The migrator that I’m writing won’t know what to do with the body of the closure passed to `pending` — since Quick doesn’t execute this closure, its contents are a black box to us.
…th-reusableTests [Groundwork for #1201] Prefix `rsh3*` function names with `reusableTests`
[Groundwork for #1201] Fix test with duplicate name
[Groundwork for #1201] Replace call to `pending` with `xit`
[Groundwork for #1201] Unroll simple test-defining loops in test files
[Groundwork for #1201] Unroll test-defining loops in test files into `reusableTests` function calls
The motivation for this change is that it’s groundwork for removing the Quick testing framework using an automated migrator tool (#1201). The migrator that I’m writing won’t know what to do with arbitrary statements at a `spec` / `describe` / `context` level. It does, however, know what to do with variable declarations. So, let’s manually move this statement inside the declaration of the variable that it’s related to.
There’s no need for these to be instance variables. We’re not mutating anything, it’s just static testing data. The motivation for this change is that it’s groundwork for removing the Quick testing framework using an automated migrator tool (#1201). The migrator that I’m writing won’t be able to handle the capture lists in the QuickSpec method call trailing closures, so I’m replacing them.
…-closure [Groundwork for #1201] Remove capture in Quick method call trailing closures
I happened to notice that these variables are only used in setting up other variables, so let’s move them inside the declaration of those variables. The motivation for this change is that it’s (not strictly necessary) groundwork for removing the Quick testing framework using an automated migrator tool (#1201). The migrator that I’m writing will pull all context-level variable declarations in a file into a single, potentially large, flattened list of declarations. So it would be nice to make this list as small as can be. (I'm not saying that the list _is_ now "as small as can be", I'm just fixing a few things that I happened to notice.)
[Groundwork for #1201] Remove floating statements at `spec` / `describe` / `context` level
[Groundwork for #1201, but also a fix] Fix setting of fallback retry timeout in tests
These variables are actually only used to set up some other variables, so we move them inside those variables’ declarations. The motivation for this change is that it’s groundwork for removing the Quick testing framework using an automated migrator tool (#1201). The migrator that I’m writing will pull all `spec` / `describe` / `context` level local variables to a single namespace for the whole file, so we need to avoid clashes. The easiest way in this particular case is to just remove the variables.
The motivation for this change is that it’s groundwork for removing the Quick testing framework using an automated migrator tool (#1201). The migrator that I’m writing will pull all `spec` / `describe` / `context` level local variables outside of the class declaration and into fileprivate global variables. But if we let the migrator hoist this particular variable to a global with the same name, then it’ll be shadowed by XCTestCase’s `name` property, which we don’t want.
[Groundwork for #1201] Rename or remove clashing variables
The motivation for this change is that it’s groundwork for removing the Quick testing framework using an automated migrator tool (#1201). The migrator that I’m writing will convert all symbols in test descriptions to underscores in the emitted method names. This is okay most of the time, but we have a few places where the symbols have meaning, and removing them will change the description of the test. The migrator emits a warning when it thinks this is the case, but it’s up to us to look at this output and decide which ones need changing.
…ve-meaning [Groundwork for #1201] Rewrite test descriptions containing meaningful symbols
What?
I'd like us to consider getting rid of the Quick testing framework.
Why?
It's a non-standard thing for new developers to learn, but more importantly it's actually making the test suite harder to maintain.
I was recently trying to investigate some tests that are intermittently failing in CI and on my machine. I wanted to see what happens when I try running these tests in isolation instead of in the full suite. Unfortunately, this wasn’t really possible because of Quick’s lack of integration with the Xcode testing UI controls. So, I think removing it would help us towards our short-term goal of identifying and quarantining flaky tests.
How?
This would be a very time-consuming thing to do manually – our test suite is big. I think it would be possible to automate it, though, using some sort of code transformation tool such as SwiftSyntax with some simple rules, to transform our
QuickSpec
subclasses intoXCTestCase
ones.I think automating it, other than saving us a heap of time, would save us from having to have disruptive code freezes whilst we migrate a file. It would also allow us to experiment with different approaches for how we’d like the migrated code to look.
I suggest that we prototype something to see whether this automation is viable.
References
┆Issue is synchronized with this Jira Uncategorised by Unito
The text was updated successfully, but these errors were encountered: