From 04ecdf834f3763e8866b156060153a5069d5549b Mon Sep 17 00:00:00 2001 From: Martin Roy Date: Thu, 24 Nov 2016 15:22:02 -0500 Subject: [PATCH 1/2] Support successive mockings for the same command By introducing a "workspace" for the mock we can have several "workspace" related values in files that describe the mock, such as the successive invocations. So now the code that is in the fake executable becomes standard and react to the content of the workspace. The support for --with-args have been completely removed and will be reintroduced in an upcoming change with tests The file sort is to ensure the tests runs the same on any machine, it would seem that "find" does not guarantee an order --- README.md | 2 +- examples/2-mocking/test/test_clean.sh | 4 +- src/cli.sh | 2 +- src/mocking.sh | 84 ++++++++++++++++++--------- test/test_mocking.sh | 72 +++++++++++++++++++++++ 5 files changed, 132 insertions(+), 32 deletions(-) create mode 100644 test/test_mocking.sh diff --git a/README.md b/README.md index e511462..b30e5ca 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ clean.sh test test_clean_works() { - mock rm --with-args "somewhere/some-file" --and exitcode 0 + mock rm --and exit-code 0 bash ./clean.sh some-file diff --git a/examples/2-mocking/test/test_clean.sh b/examples/2-mocking/test/test_clean.sh index 67ae61e..774927a 100644 --- a/examples/2-mocking/test/test_clean.sh +++ b/examples/2-mocking/test/test_clean.sh @@ -1,7 +1,7 @@ #!/bin/bash test_clean_works() { - mock rm --with-args "somewhere/some-file" --and exitcode 0 + mock rm --and exit-code 0 bash ./clean.sh some-file @@ -9,7 +9,7 @@ test_clean_works() { } test_clean_works_fails() { - mock rm --with-args "somewhere/non-existing-file" --and exitcode 1 + mock rm --and exit-code 1 bash ./clean.sh non-existing-file diff --git a/src/cli.sh b/src/cli.sh index 9db83c9..65b6b2e 100755 --- a/src/cli.sh +++ b/src/cli.sh @@ -38,7 +38,7 @@ if [ -z "${RUN_SINGLE_TEST:-""}" ]; then registry="$(mktemp -d "/tmp/workspace.registry.XXXXXXXX")" test_count=0 - for f in $(find ${test_sources_root} -name "${test_suites_filter}"); do + for f in $(find ${test_sources_root} -name "${test_suites_filter}" | sort); do TEST_ROOT_DIR=${test_sources_root} RUN_SINGLE_TEST=1 $0 ${sources_root} ${f} ${test_filter} ${registry} || fail "${f} failed." new_tests=$(cat ${registry}/test_count) diff --git a/src/mocking.sh b/src/mocking.sh index 72f91e8..c81c41b 100644 --- a/src/mocking.sh +++ b/src/mocking.sh @@ -1,47 +1,75 @@ -mock-exitcode() { +action-echo() { + text="$@" + cat < ${mocks}/${executable} - mock ${executable}-then --and exitcode "${and_params}" + if [ ! -d ${mock_workspace} ]; then + mkdir -p ${mock_workspace} + echo "1" > ${mock_workspace}/invocation_index + + _mock_handler ${mock_workspace} > ${mocks}/${executable} + chmod +x ${mocks}/${executable} + + invocation_count=1 else - mock-${mock_type} "${and_params}" > ${mocks}/${executable} + ((invocation_count=$(cat ${mock_workspace}/invocation_count) + 1)) fi - chmod +x ${mocks}/${executable} -} + echo ${invocation_count} > ${mock_workspace}/invocation_count + invocation_file="${mock_workspace}/invocation_${invocation_count}" + + echo "#!/bin/bash" > ${invocation_file} + + for i in ${!actions[@]}; + do + action-${actions[$i]} ${actions_params[$i]} >> ${invocation_file} + done -_mock_assert_args() { - expected_args=$1 - and=$2 + chmod +x ${invocation_file} +} + +_mock_handler() { cat < expectation_failure +workspace=$1 +invocation_index=\$(cat \${workspace}/invocation_index) + +if [ \${invocation_index} -lt \$(cat \${workspace}/invocation_count) ]; then + echo \$((invocation_index + 1)) > \${workspace}/invocation_index fi + +\${workspace}/invocation_\${invocation_index} EOF } diff --git a/test/test_mocking.sh b/test/test_mocking.sh new file mode 100644 index 0000000..7c336a9 --- /dev/null +++ b/test/test_mocking.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +test_mocking_a_command_with_a_success_exit_code() { + mock some-command --and exit-code 0 + + some-command + assert ${?} succeeded +} + +test_mocking_a_command_with_a_failure_exit_code() { + mock some-command --and exit-code 1 + + some-command + assert ${?} failed +} + +test_mocking_a_command_to_return_a_value_and_exit_success() { + mock some-command --and echo "hello" --and exit-code 0 + + result=$(some-command) + assert ${?} succeeded + + assert "${result}" equals "hello" +} + +test_mocking_a_command_to_return_a_value_and_exit_failure() { + mock some-command --and echo "hello" --and exit-code 1 + + result=$(some-command) + assert ${?} failed + + assert "${result}" equals "hello" +} + +test_mocking_several_times_the_same_command() { + mock some-command --and exit-code 0 + mock some-command --and exit-code 1 + mock some-command --and exit-code 0 + + some-command + assert ${?} succeeded + + some-command + assert ${?} failed + + some-command + assert ${?} succeeded +} + +test_no_mock_count_mocks_all_the_calls() { + mock some-command --and exit-code 0 + + some-command + assert ${?} succeeded + + some-command + assert ${?} succeeded +} + +test_mocking_a_second_time_assume_the_first_was_a_one_time_and_mocks_all_other_calls() { + mock some-command --and exit-code 1 + mock some-command --and exit-code 0 + + some-command + assert ${?} failed + + some-command + assert ${?} succeeded + + some-command + assert ${?} succeeded +} From 1b803431b42d9935f3c514bc965774bf8243982a Mon Sep 17 00:00:00 2001 From: Martin Roy Date: Thu, 24 Nov 2016 16:47:44 -0500 Subject: [PATCH 2/2] Validate arguments on mocks This is the first working version, will only support ordered successive calls, upcoming change should have param-base action triggers --- README.md | 2 +- examples/2-mocking/test/test_clean.sh | 4 +- src/mocking.sh | 44 ++++++++++++++++--- test/test_mocking_args_matching.sh | 23 ++++++++++ ...g.sh => test_mocking_multi_invocations.sh} | 0 5 files changed, 63 insertions(+), 10 deletions(-) create mode 100644 test/test_mocking_args_matching.sh rename test/{test_mocking.sh => test_mocking_multi_invocations.sh} (100%) diff --git a/README.md b/README.md index b30e5ca..8e83e3c 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ clean.sh test test_clean_works() { - mock rm --and exit-code 0 + mock rm --with-args "somewhere/some-file" --and exit-code 0 bash ./clean.sh some-file diff --git a/examples/2-mocking/test/test_clean.sh b/examples/2-mocking/test/test_clean.sh index 774927a..e03c14a 100644 --- a/examples/2-mocking/test/test_clean.sh +++ b/examples/2-mocking/test/test_clean.sh @@ -1,7 +1,7 @@ #!/bin/bash test_clean_works() { - mock rm --and exit-code 0 + mock rm --with-args "somewhere/some-file" --and exit-code 0 bash ./clean.sh some-file @@ -9,7 +9,7 @@ test_clean_works() { } test_clean_works_fails() { - mock rm --and exit-code 1 + mock rm --with-args "somewhere/non-existing-file" --and exit-code 1 bash ./clean.sh non-existing-file diff --git a/src/mocking.sh b/src/mocking.sh index c81c41b..eddfb8d 100644 --- a/src/mocking.sh +++ b/src/mocking.sh @@ -1,4 +1,3 @@ - action-echo() { text="$@" cat < +Expected : <"${expected}"> +OUT + exit 1 +fi +EOF +} + mock() { local executable=$1; shift local actions=() local actions_params=() local action_count=0 + local has_args_validation=false while [[ $# -gt 0 ]]; do - key="$1" + local key="$1" case ${key} in --and) - actions[$action_count]="$2" + actions[$action_count]="action-$2" actions_params[$action_count]="$3" shift; shift ((action_count=action_count + 1)) ;; + --with-args) + if [ ${has_args_validation} == false ]; then + actions[$action_count]="validate-args" + actions_params[$action_count]="$2"; shift + ((action_count=action_count + 1)) + has_args_validation=true + else + echo "Cannot expect more than 1 set of argument for an invocation, please use 'mock' multiple times" + return 1 + fi + ;; esac shift done @@ -52,9 +80,8 @@ mock() { echo "#!/bin/bash" > ${invocation_file} - for i in ${!actions[@]}; - do - action-${actions[$i]} ${actions_params[$i]} >> ${invocation_file} + for i in ${!actions[@]}; do + ${actions[$i]} ${actions_params[$i]} >> ${invocation_file} done chmod +x ${invocation_file} @@ -63,13 +90,16 @@ mock() { _mock_handler() { cat < \${workspace}/invocation_index fi -\${workspace}/invocation_\${invocation_index} +\${workspace}/invocation_\${invocation_index} \${args} EOF } diff --git a/test/test_mocking_args_matching.sh b/test/test_mocking_args_matching.sh new file mode 100644 index 0000000..e3cfeb0 --- /dev/null +++ b/test/test_mocking_args_matching.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +test_fails_if_given_arguments_isnt_right() { + mock some-command --with-args "one two three" + + some-command three two one > assertion_output + assert ${?} failed + + expected_error=$(cat <<-EXP +Unexpected invocation for command 'some-command': +Got : <"three two one"> +Expected : <"one two three"> +EXP +) + assert "$(cat assertion_output)" equals "${expected_error}" +} + +test_fails_if_2_with_args_argments_are_given() { + mock some-command --with-args "a" --with-args "b" > error + assert ${?} failed + + assert "$(cat error)" equals "Cannot expect more than 1 set of argument for an invocation, please use 'mock' multiple times" +} diff --git a/test/test_mocking.sh b/test/test_mocking_multi_invocations.sh similarity index 100% rename from test/test_mocking.sh rename to test/test_mocking_multi_invocations.sh