Mocking and Stubbing Source Code

When putting a program under test, sometimes you may only need to run portions of its code, or perhaps a simplier, more efficient piece of code could be used in its place that returns the required data. If either of these scenarios are the case, you should consider mocking and stubbing the source program.

Mocking enables you to control the execution of source during a test run, skipping code you do not need to run, and replacing other portions with your own bespoke code for the duration of the test run (stubbing); for example, instead of running code that searches a database for a customer record, you could simply replace that portion of code with some that returns data equivalent to a single record. Such techniques can hugely improve the efficiency of your test runs, and none of these features require you to actually edit the source code program.

Firstly, to mock the source program, it must be compiled using the MFUPP preprocessor with the MOCK directive set. The rest of the configuration occurs in the test case itself.

The test case needs a controller to control the flow of execution, and (optionally) a redirector to run alternate 'stubbed' code. Both the controller and the redirector are entry points in the test case, determined by the MFU-MD-PP-CONTROLLER and MFU-MD-PP-REDIRECTOR metadata fields.

The controller entry point is executed each time you call into your source program or entry point during the test run.

Within the controller entry point, special return values allow you to control the flow of execution. For example, the following excerpt shows all three possible values (prefixed MFU-PP-ACTION) that can control the flow:

entry "MOCK-CONTROLLER" using by reference lnk-program-to-mock
                                by value lnk-program-to-mock-len.

    evaluate function upper-case(lnk-program-to-mock(1:lnk-program-to-mock-len))
        when "GETCUSTOMERID"
            goback returning MFU-PP-ACTION-REDIRECT
        when "LOGINPROMPT"
            goback returning MFU-PP-ACTION-GOBACK
    end-evaluate

    goback returning MFU-PP-ACTION-DO-NOTHING.

If the test is currently calling LOGINPROMPT, execution should skip it and continue (evidenced by the MFU-PP-ACTION-GOBACK action); if the test is currently calling GETCUSTOMERID, execution should be redirected (to the redirector) instead of running that particular piece of code (evidenced by the MFU-PP-ACTION-REDIRECT action); and if none of those evaluate statements are true, execution continues as normal (evidenced by the MFU-PP-ACTION-DO-NOTHING action).

When the MFU-PP-ACTION-REDIRECT action is true, control is passed to the redirector entry point:

       entry "MOCK-REDIRECTOR" using by reference lnk-redirect-to
                                     by value lnk-redirect-to-len
                                     by reference lnk-who
                                     by value lnk-who-len.

           string "MOCK-" delimited by size
                   lnk-who(1:lnk-who-len) delimited by size
                   into lnk-redirect-to(1:lnk-redirect-to-len)
           end-string
           inspect lnk-redirect-to(1:lnk-redirect-to-len)
               replacing all "@" by "-"

           goback.

       entry "MOCK-getCustomerId" using lnk-lastname,
                                        lnk-customer-id
                                   .
           move 0 to lnk-customer-id
           evaluate lnk-lastname
               when "Smith"        move 42 to lnk-customer-id
               when "Jones"        move 21 to lnk-customer-id
           end-evaluate
           
           goback.

The above excerpt is an example redirector, where the stubbed code returns some hard-coded customer details; this could replace code in the source program that performs a search of a large database, and returns 'live' information.

See Using MFUPP to Mock and Stub a Program for a fuller example of source code under test that uses these techniques.