-
Notifications
You must be signed in to change notification settings - Fork 5
Description
Hello 👋
I really like this project, especially because it separates the test execution engine completely from the test code. Incidentally, it seems like this separation would also make it possible to implement mocking support in nutest!
A little aside on why: I've found that as complex scripts grow, it gets more difficult to rely on using aliases to redefine external commands only; additionally, most external commands return unstructured data and are therefore significantly more inconvenient to mock directly.
I started sketching out a proof of concept here: https://github.com/spion/numock
The main idea
- Test files that declare the need for mocking (e.g. through exporting a constant specifying which modules under test will need mocks) will be copied to a temporary directory, together with the specified modules
- The specified module-under-tests' non-mocked dependencies are also copied (PoC uses
NU_LIB_DIRSbut i realized later this will be error-prone, so the other dependencies need to be copied too) - The mocked dependencies are not copied - instead, they're replaced with proxies that call out to the original modules if there is nothing in the "mocking registry", but call a closure in the mocking registry if its present instead.
- A "numock" module provides API to reset the mocks or redefine them
What this allows is to swap the implementation at run-time and test a variety of situations for commands that do complex orchestration of multiple side-effects!
Potential improvements
- Dependencies can be autodetected (parsing
useinstrcutions?), and all dependencies could be proxied back to the original directory. - Individual functions within a module can also be mocked by replacing the implementation in its source (
view sourceis generally accurate after the function signature block) - The current approach needs to recreate the entire tree containing the common root of the module under test, mocked dependencies and the test itself. This might be a problem, and rewriting
useinstructions to different paths might end up being easier instead. (Note that the current PoC implementation is simplistic and doesn't do that - it simply assumes the test, module under test and mocks are in the same directory)
Implementation idea
In terms of impementing this for nutest, I don't think it would be too hard. Here is one potential idea I've been looking into:
- The discover phase will discover the type of tests in addition to their other attributes
- A new "preparation" phase will exist between discover and the orchestrator, which will prepare the tests that request mocks into a new temporary directory, and enrich the test description objects with a new attribute (e.g. execution_path),
- The orchestrator will prefer execution_path over path when executing the tests
Only tests that explicitly declare they need mocking would be processed by the processor - the rest would work normally.
What do you think? Also, do you know if there a simpler way to achieve mocking in nushell that I've missed?