Vladimir Dyuzhev, author of MockMotor

Vladimir Dyuzhev
MockMotor Creator

Tweak it, Don't Mock it!


To test against a future version of an API, alter a live response instead of recreating it as a mock

Using mocks, you can decouple layers and develop the code faster, not waiting for the other party.

For example, a frontend code is ready to call a to-be-updated service. However, the service code is not ready yet, and the frontend team has to wait. This delay is annoying and a waste of time. But you can unblock the frontend by giving it mocks.

The straightforward approach is to mock the whole service for all required test accounts. But that can be lots of responses.

Is there a way to minimize your work and yet let the project team move ahead?

Yes, there is.

Tweaking the Responses

If the expected change is a small modification of the existing response, you can tweak the live responses instead of providing a complete mock.

It has a few benefits:

  • The data seeding is immediately reflected in our mocks because they are also live responses.
  • The project-related modifications are also in the mocks because you put them there!
  • The mock payload script is small and readable because you only tweak and not recreate.

Here is How it Works

MockMotor supports forwarding to live test service. Usually, the response from the live service is sent to the caller as-is.

However, MockMotor can also modify that response - add an element or change a value, or rewrite it completely.

After the forward, the $output variable contains the response. The payload script, if it is not empty, rewrites it, creating a tweaked or completely new $output content.

Then your solution can be simple:

  • Point the application to MockMotor
  • Make MockMotor forward all requests to a live test backend
  • Modify some of the live responses to satisfy the project's requirements
  • Let all other responses fly back unmodified

Viola! You've made a future-versioned mock service with minimum efforts.

At the time of this writing, MockMotor doesn't support tweaking the requests sent to the live backends. A pity. Sometimes it is the frontend that is behind schedule, and the backend is ready to receive the updated calls. I plan to address it in some not-so-distant-future version.

This is not only for DIT/SFT

This works best for DIT and SFT stages, where we can route the traffic to live test systems. In LT or PT environments, you need to have standalone mocks.

But the good news is: once you have those mocks working in functional testing environments, you can save the responses as complete mocks and use them in LT!

Example: Injecting Message Codes

I was recently asked to help with expedited testing of error-handling scenarios - a rather large number of them.

The application received informational codes from a backend and presented them to the user. The problem was that seeding test accounts that produce those codes is time-consuming, and the project only had two days left in the testing phase.

I suggested that MockMotor injected those codes into the live DIT test responses based on the account number. The account-based approach has an extra benefit that QA can continue testing on other accounts. That is impossible with the traditional error testing (shutting down subsystems and such.)

My plan was:

  • MockMotor passes all traffic to the live DIT backend as is.
  • When it encounters an account that has a code to be tested, MockMotor alters the response by injecting that code.

Here is how I did that, step by step.

Setting up the Mock Accounts

The test scenarios are defined as “Login with TV account N. Expectation: message M is shown.” Hence the accounts in the application are identified by the TV number.

I set up three mock account properties:

  • tv: the account number
  • messageCode: the injected code
  • messageText: the corresponding message description (not used for UI, but I still provided it for completeness)

Then I populated these accounts with data from the QA test spreadsheet - account number, expected code, description.

Setting up the Default Forward

I only needed to tweak the responses for a specific operation - getQualificationData. Everything else should flow to the backend unmodified.

That is achieved by the catch-all forward reaction, which matches all requests and forwards them to the live backend.

I placed this reaction last in the reactions list.

Setting up the Tweaking Forward

The request that I need to intercept has one key element - TV account number:

      <getQualificationData>
        ...
        <customerQualificationRequest>
            <customerIdentifier>
               <televisionAccountNumber>8457800600272052</televisionAccountNumber>
            </customerIdentifier>
            ...

The tweaking mock checks that the request is the right operation and that the account is configured for the tweak:

  • The HTTP method is POST
  • The operation (first payload element) is getQualificationData
  • There is an account with the tv property matching the request's televisionAccountNumber value and a non-empty messageCode

If either of these conditions is not met, the tweaking reaction is skipped, and the request is handled by the default forward reaction.

For instance, if there is a mock account for TV 8457800600272052, but it has no messageCode set, the tweaking reaction doesn't match, and the request is handled by the next mock reaction (which forwards it to the backend as-is).

Injecting the messageCode

How do I update the response after MM receives it from the live backend?

With XQuery, I have to rebuild the response, replacing the elements that I need to modify.

XQuery supports updates to XML, but MM doesn't have support for updatable XML yet. Sorry.

After the call to the backend, the response is stored in the $output (a.k.a. $response) variable. I can rebuild its content simply by providing the payload script. The script execution result will be assigned back to $output. Then the new $output is sent to the caller.

Here's the payload script I have for the tweaking response:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Body>

<getQualificationDataResponse>

{
for $e in $output//*:getQualificationDataResponse/*
return
  if( local-name($e) = 'responseMessageList' ) then (
            <responseMessageList>
            <messageItemList>
               {
                 for $mc at $idx in $account/*:messageCode
                 return
                     <messageItem>
                     <messageCode>{$account/*:messageCode[$idx]/text()}</messageCode>
                     <messageText>{$account/*:messageText[$idx]/text()}</messageText>
                     <messageLanguage>English</messageLanguage>
                     </messageItem>
               }
            </messageItemList>
            <totalMessages>1</totalMessages>
            </responseMessageList>
  ) else ( $e )
}

</getQualificationDataResponse>
 </soapenv:Body>
</soapenv:Envelope>

What I do here is iterate every element in the $output under the getQualificationDataResponse and check its local name. If it is anything but responseMessageList, I copy it to the result (the ... else ( $e ) section.)

However, if I encounter responseMessageList, I drop the original content of it and create my own version, with the messageCode value that comes from the account.

The end result is that I copied all elements that came from the backend, except for responseMessageList, which I replaced.

The Final Reactions

The whole work took a couple of hours and helped to improve the project status from YELLOW to GREEN.

My two forwarding responses are looking as below. As you can see, MockMotor tweaked 140 responses and passed over three thousand to the backend unmodified.