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
waitForPromises() should be removed #76
Comments
Hi Vladimir, if I'm not mistaken, you're concerned about a test case (presumably, integration one?) where the user may create a bunch of promises internally, which may not be related directly to the functionality being tested, and thus create a race condition when My take on that is the user should be well aware of what Thanks. |
@shoumikhin Yes, I'm concerned about that test case which will be quite common for any complex asynchronous system (and async code is complex by default). Also I'm concerned that that method will be used in production code of that system (for example, in SDK), which will create deadlock if I will use your Promises library in my app that uses SDK that uses your library too.
And also most incorrect one, so everyone will be accustomed to incorrect way from the start. You cannot determine that all promises are completed anyway (so method name is a lie) due to fundamental Halting Problem: just after waitForPromises() return, some background thread/queue can just create yet another promise. |
Not sure I get why you consider it incorrect? Any examples? Also, why do you think that method is gonna be used in production? It's located in a separate header in Objective-C, and is internal in Swift, so you can't just leverage it for anything w/o explicitly importing a test-only declaration. I totally get that another promise can be created after |
Yes, consider that iOS would have following method of NSThread class for async testing:
And that Apple would recommend its usage in XCTest documentation as simplest way to write asynchronous test. You cannot wait for ALL threads and promises, even in tests, because threads and promises are ALWAYS implementation detail that may not be visible to the test and that are thus prone to race conditions from test's point of view.
Or tested code can create arbitrary number of promises while you're waiting in waitForPromises(). And it would do it as part of its CORRECT operation. That's the core problem: you cannot distinguish freeze of the system from its correct operation. That was proved by Alan Turing in 1936: https://en.wikipedia.org/wiki/Halting_problem Your method waitForPromises() incorrectly implies directly opposite to that.
No, you would not find that bug, because it will be the result of asynchronous race condition by definition. Or your waitForPromises() would just hang sometimes for arbitrary amount of time for CORRECT tests with CORRECT code. |
Sorry, if I understand you correctly, your concern around Do you suggest to refine the docs then, and explicitly recommend using XCTest instead if unsure or facing issues with |
No, my concern is that any use of waitForPromises() is inherently incorrect, because it implies wrong assumptions that:
In overall, this method represents completely incorrect way of writing async tests: instead of waiting for the overall state of the async system (which is prone to deadlocks and race conditions) you must wait for particular events from it. XCTestExpectation does exactly that.
No, I suggest removing waitForPromises() entirely, because its testing paradigm is entirely incorrect and also useless on platform that have perfect async code testing capabilities like XCTestExpectation. And current waitForPromises() implementation is awful anyway because it works like spinlock and eats CPU for breakfast, which will lead to excessive CI server usage. So nothing will be lost from its removal anyway. |
Sure, so you may perceive |
It is not an event, it is implementation detail of the tested code, which may change without changing code's correct external behaviour. Therefore, waitForPromise() should not be used in tests, because it makes tests dependable on hidden implementation details of tested code. |
I think it really depends on how you look at it and what exactly you test. Sounds like you're talking about some integration tests and check for a specific set of events to happen, while ignoring the others. And you also don't expect a test to change much while working on implementation details. Surely, |
No, I'm talking about the fact that test should not depend on tested code's implementation details that it cannot see. Your promises can (and will) be used in implementation of classes that return OTHER promises via external public API. waitForPromises() will immediately lead to incorrect behaviour of tests in that case. Because it uses fundamentally wrong testing paradigm. |
I see. Well, |
My position is that it should be removed from library, not have changed just changed docs. So no PR. :) Exposing internal events to test can be done via Swift’s internal keyword and following import: ’’’ |
Sounds good, happy to hear other opinions, so let this issue hang for a while. |
@virl thank you for the discussion! After discussing this further, we believe there are valid use cases where developers would want to use Additionally, to make the intention of the If you have any additional proposals to help make the API more clear, please feel free to submit a PR with the changes. Thank you! |
waitForPromises() should be removed because it is an abstraction leak: you never know in the test what other promises tested code will use in it internal implementation.
"So waiting for a bunch of async tasks to finish in a test can be tricky." (from docs) — no, it is tricky on Android that doesn't have any SDK support for it.
On iOS, we have XCTestExpectation exactly for that, without false hope for tested code to move into predictable state by leaking its implementation details into the test.
The text was updated successfully, but these errors were encountered: