Performing behavior verification using mocks

Mocks are different from stubs rather than just testing the return value of a function, we focus on testing expectations from the collaborator functions' perspective. What kind of activities does a collaborator function expect? Here are some examples for our use case:

  • From the check_background function's perspective, was it called only once for each open_account call?
  • From the create_account function's perspective, was it called when a background check was successful?
  • From the create_account function's perspective, was it not called when the background check failed?
  • From the notify_account function's perspective, was it called with an account number that is greater than 0?

The process to set up a mock-enabled test involves four main steps:

  1. Set up the mock functions that will be used during the test.
  2. Establish the expectations for the collaborator functions.
  3. Run the tests.
  4. Verify the expectations that we set earlier.

Now, let's try to develop our own mock test. Here, we will exercise the success path for opening a new account. In this case, we can expect the check_background, create_account, and notify_downstream functions to be called exactly once. Also, we can expect that the account number being passed to the notify_downstream function should be a number greater than 1. Keeping this information in mind, we will create a let-block with bound variables to track everything that we want to test against our expectations:

let check_background_call_count  = 0,
create_account_call_count = 0,
notify_downstream_call_count = 0,
notify_downstream_received_proper_account_number = false

# insert more code here...
end

The first three variables will be used to track the number of calls to the three mocks that we are about to create. Also, the last variable will be used to record whether the notify_downstream function received a proper account number during the test. Within this let-block, we will implement the four steps we outlined previously. Let's define the mock functions first:

check_background_success_patch = 
@patch function check_background(first_name, last_name)
check_background_call_count += 1
println("check_background mock is called, simulating success")
return true
end

Here, we just increment the check_background_call_count counter within the mock function so that we can keep track of how many times the mock function is called. Similarly, we can define the create_account_patch mock function in the same way:

create_account_patch = 
@patch function create_account(first_name, last_name, email)
create_account_call_count += 1
println("create account_number mock is called")
return 314
end

The last mock function, notify_downstream_patch, covers two expectations. Not only does it keep track of the number of calls, but it also verifies that the account number being passed is proper and, if so, updates the Boolean flag. The following code shows this:

notify_downstream_patch = 
@patch function notify_downstream(account_number)
notify_downstream_call_count += 1
if account_number > 0
notify_downstream_received_proper_account_number = true
end
println("notify downstream mock is called")
return nothing
end

The second step is to establish our expectation formally. This can be defined as a simple function, as follows:

function verify()
@test check_background_call_count == 1
@test create_account_call_count == 1
@test notify_downstream_call_count == 1
@test notify_downstream_received_proper_account_number
end

The verify function includes a set of expectations, formally defined as regular Julia tests. Now, we are ready to exercise our test by applying all three mock functions:

apply([check_background_success_patch, create_account_patch, notify_downstream_patch]) do
@test open_account("peter", "doe", "[email protected]") == :success
end

Finally, as the very last step, we will test against our expectation. It is simply a call to the verify function that we defined earlier:

verify()

Now, we are ready to run the mock test. The respective results are as follows:

The result statistics show five test cases in total and all of them passed. Four out of the five tests came from the verify function for behavior verification, while one came from the state verification for the return value of the open_account function.

As you can see, mocks are quite different from stub because they are used to perform both behavior and state verifications. 

Next, we will look into a pattern that's related to how data pipelines can be built more intuitively.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.12.71.237