codehearts / shpy Goto Github PK
View Code? Open in Web Editor NEW🕵️♀️ POSIX compliant spies and stubs for shell unit testing
Home Page: https://hub.docker.com/r/shpy/shpy
License: MIT License
🕵️♀️ POSIX compliant spies and stubs for shell unit testing
Home Page: https://hub.docker.com/r/shpy/shpy
License: MIT License
Shellcheck warns about using local
, but there's no problem with us using it. That warning should be disabled in our default invocation of shellcheck.
Also take this chance to set up shellcheck with HoundCI. We'll need a .hound.yml
and a yaml file for the shellcheck warnings to ignore
As a user, I'd like to mount my scripts as read-only in the container I'm testing in. This isn't seamless because shpy tries to create temp directories in the current working directory
Hi,
Thanks for an amazing framework, it helped me refactoring tons of shell scripts that overwise were hopeless.
I run into small issues while developing on Mac. The wc util has a nasty behavior on Macs where its return contains leading spaces, as described here https://stackoverflow.com/questions/30927590/wc-on-osx-return-includes-spaces
This makes the output of _shpyGetDirectoryContentsCount
function incorrect, which breaks counts when there are multiple spy calls.
I can submit PR, but I'd like to know if this is something worth fixing. I guess people may run into this if they develop on Macs?
Thanks!
When a spy is invoked, record the arguments it was invoked with and then execute (call through to) the original function/command.
This will only ever work with a shell that supports something like declare -f
or typeset -f
, so dash
and posh
support is a no-go.
Discovered this while writing practical use examples for new users. Shpy works great for shell libraries you source into a script, but is unable to handle executable shell scripts which run in a separate shell process
Modify shpy to support this case. I have a feeling it might be one of the more common use cases
It would be really nice to have a simplified overview of how shpy works, how it creates the stubs, how it tracks calls, stubs outputs, etc. This should go in the development section of contributing.md
I was looking how to refactor ol’ scripts without too much rewriting and have functions there tested separately. The easiest way was to source target script (with some logic to prevent it running everything) and then do usual spy/asserts for each function.
However, if functionA calls functionB which calls functionC - then spy for functionB is ignored because I think bash first calls sourced functions and then one in PATH.
Workaround is to remove all nested functions with ‘unset -f functionB’ inside each test.
I wonder if that’s something framework can handle, maybe with a flag?
Spy output is currently stored on disk, but they could theoretically be stored in memory as _shpy_${spy_name}_stdout_${index}
to avoid disk access
Try looking into the following:
SHPY_RUN_MODE=memory|disk
flag, or made default?Don't forget to update CONTRIBUTING.md
to detail the new inner workings!
Docker is introducing an image retention policy for free plans (of which the shpy organization on Docker Hub is) that will remove images which have not been pushed or pulled in 6 months. I agree with the policy of removing unused images, but would like shpy to hang around for developers who discover it to have easy access
I haven't checked if this is really an issue or not (I'm not sure how often our image is used), but worst case we can always auto-publish every few months. I think this makes sense, too, because we'll automatically be kept up to date with the latest versions of supported shells
Once #15 is done, publish Docker containers for each release and for the latest master node. The container should make it easy for devs to test their scripts with shpy and shunit2 under the more common shells (sh, dash, bash, zsh, maybe fish? ksh? csh?)
There are three more instances where undefined variables aren't checked in a way that works with the nounset
flag
Example (dummy_test):
testDummy() {
set -o nounset
cleanupSpies
}
Output:
# dummy_test: 147: eval: _shpy_spies_dir: parameter not set
The other two instances involve createSpy
: if a return value is passed via -r
, and if no spy name is passed
I'm trying to stub a function which prints its expected output to STDERR, but it doesn't look shpy supports this. Would it be reasonable to add an -e STDERR_OUTPUT
option, which would be printed in addition to output from -o
?
It would be nice to have a way to get the actual arguments that were passed to the mock for call X
For example:
createSpy some_spy
some_spy foo
some_spy
some_spy bar -a foo -baz
getArgsForCall some_spy 1
# foo
getArgsForCall some_spy 2
#
getArgsForCall some_spy 3
# bar -a foo -baz
I've been working with Rust lately, and having rustfmt
reformat code has been a godsend. I've noticed shpy
has differing indentation levels and coding styles from file to file, it'd be nice to run and enforce shfmt for consistency
I'm really liking shpy so far, especially its support for subshells! I have a function which calls a stub multiple times, and I'm not able to test cases where the stub returns a different value on subsequent calls.
My thought would be supporting a createSpy -r 0 -r 1 -r 2 spyName
syntax, and always return the last value after finishing the sequence.
Testing uses like, 5 or 6 different Docker images. Docker Compose would manage these for us, provide parallel pulls, and perform parallel testing with output that can be filtered as needed all under docker-compose up
This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.
These updates have all been created already. Click a checkbox below to force a retry/rebase of any.
docker-compose.yml
Dockerfile
koalaman/shellcheck v0.8.0
alpine 3.17.3
kcov/kcov v40
alpine 3.17.3
.github/workflows/test.yml
actions/checkout v3
actions/checkout v3
codecov/codecov-action v3
As a dependency for developers looking to test their scripts, it's wild for shpy
to not be versioned. Tag some node as 1.0.0 and we can go from there
shpy already supports ash and mksh, so this should be as simple as pulling the shell binaries into the Docker container and adding new Docker compose services and Travis CI matrices
If the nounset
bash option is set, spies will fail due to checking of undefined variables.
Example:
#!/usr/bin/env bash
set -o nounset
testNoUnset() {
createSpy some_cmd
some_cmd
}
. ../shpy/shpy
. ../shpy/shpy-shunit2
. ./shunit2
Output:
testNoUnset
../shpy/shpy: line 153: _shpy_inited: unbound variable
ASSERT:unknown failure encountered running a test
Ran 1 test.
FAILED (failures=1)
Similar to the current ability to return a sequence of values with
createSpy -r 4 -r 3 -r 9 some_command
we should be able to pass in a sequence of outputs, which will be printed to stdout on successive calls to the mock, in the order they are passed.
For example:
createSpy -o "foo bar" -o "abc def" some_command
some_command
# foo bar
some_command
# abc def
some_command
# abc def
This may be blocked by #14, since a shpy container would make it easy to control and debug our kcov environment. Looks like kcov isn't behaving properly and is spewing output to stdout when it should be in PS4 or something, which causes builds to fail with no reporting data
Things to note:
itShowsUsageWhenCreatingSpyWithoutArgs
t/
should be renamed to test/
for clarity, and to make it easier to click on GitHub honestlyUnit testing is still relatively new to the shell scripting world. The average shell programmer isn't going to know what unit testing is for and when you would use it, so it's even more unlikely that they'd know why you would want to use spies and stubs.
There needs to be a concise yet complete introduction to shell unit testing with spies and fakes that not only explains how to use the functions in shpy, but it would also explain:
I feel like I know what needs to be said, but at this point I still need to think of a programming problem that:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.