Mocking/faking a Natural module at runtime

Happy new year to everyone! :slight_smile:

I have two technical questions I couldn’t find a solution for myself and I hope you can help me out.

Background: I want to “mock” a Natural module at runtime. A module “A” calls another module “B”, which accesses the database. I would like to test module “A” without it calling “B” and therefore accessing the database. I could pass a parameter with the module name to call to “A” (e.g. #P-TO-CALL and then do a CALLNAT #P-TO-CALL), but that means I would have to change “A”'s interface (add a parameter to “A”), which I don’t want. Furthermore, this technique would only work for subprograms and not for external subroutines, as dynamically calling a subroutine from a variable name is not possible (at least as far as I know).

So, I would like to be able to have “A” call “B” in production code and a mocked/fake/stub version of “B” that returns well-known values in test code. All from within a running Natural session. Finally, here are my two questions:

  1. Is it possible to manipulate the target of a CALLNAT/PERFORM at runtime, so that another module instead of the given one is called? Perhaps I could teach Natural to call “C” whenever “CALLNAT B” is executed. If so, my second question would perhaps be irrelevant.

  2. Does anyone know if it is possible to compile Natural sources programmatically from within a running Natural session AND call the newly compiled module directly afterwards?

Because I have absolutely no idea whether 1) is possible, I experimented with 2) a bit and found two ways of creating, saving and stowing Natural modules at runtime: either by putting Natural commands like READ, SAVE and STOW on the stack myself (using STACK TOP COMMAND etc.) or by using the corresponding User Exits like USR0210N (“Save, catalog or stow Natural object”), which - as far as I understand them - are only wrappers around the manual stack commands themselves. I’ve managed to create a new module and stow it, but unfortunately it can’t be called from within the same Natural session, as the documentation for USR0210N states:

Any help on how to “mock” a Natural module at runtime would be much appreciated!

Best regards,
Stefan

PS: I’ve managed to program a working solution for mocking a Natural module in our Linux environment, but it calls a Bash script, that starts a second Natural batch session for compiling the module to mock. However, this solution is too slow (about 1s per mock) for production use.

Hi Stefan - and a happy new year to you as well :wink:

ad 1)
I assume this is for testing purposes - right ?
In that case you might be able to achieve this using a Steplib approach/workaround.

If you have your own “private” library (either in NaturalONE terms or just a testing library) with steplib to the “prod” lib.

Then if you place your “A” program and a “C” program - with the same name as “B” in this lib then you should be able test your “A” program without calling the “prod” B.

Another option might be to use +variables (independent) or an optional parameters in the parameters for subprogram “B”.

ad 2) Have you considered Dynamic Source Code Generation ?
This was part of the old Natural II training, where you use +variable to build your sourcecode and the “run” a the program (and it MUST be a program because it is “fetched” !).

Here is the example program from the old training that use the +variable +CRITERION with the interesting “&” prefix for this specific usage.

FIND CRUISE-V WITH &CRITERION
IF NO RECORDS FOUND
WRITE ‘no hits’
ESCAPE BOTTOM
END-NOREC
DISPLAY START-HARBOR START-DATE
END-FIND

I can supply the full modules if it is interesting…

regards
Finn

Hi Finn,

thanks for your quick answer!

Yes, I want to extend our unit test framework NatUnit to be able to mock modules from within our unit tests. My working prototype (using Bash scripts for “mocking”) looks like this:

********************************************************************************
IF NUTESTP.TEST EQ 'Test with Mock'
********************************************************************************
  /* module to mock
  MOCKMODP.LIBRARY := *LIBRARY-ID
  MOCKMODP.MODULE := 'TOMOCK'
  /* everything after "END-DEFINE" in above module will be replaced by this code
  MOCKMODP.CODE :=
  '#RESULT := "The MOCKED module"' - H'0A' -
  'COMPRESS #RESULT "2" INTO #RESULT' - H'0A'
  PERFORM MOCK-MODULE NUASSP MOCKMODP
*
  CALLNAT 'TOTEST' #RESULT /* -> does a CALLNAT 'TOMOCK', which returns "The REAL module"
  ASSERT-LINE := *LINE; PERFORM ASSERT-STRING-EQUALS NUASSP 'The MOCKED module 2' #RESULT
*
END-IF
********************************************************************************

The StepLib approach would not solve my problem, because I need to create/stow the new module at runtime. The mocked code should not be defined in an already present module in a different lib, because that would make the test harder to understand (I would have to read the test case AND the mock module instead of only the test case).

Using independent variables/parameters would also not solve the problem, due to the same reason. In addition to that, the module references (Xref, “A” calls “B”) would not be available, because “A” does a “dynamic” CALLNAT.

I haven’t heard of “Dynamic Source Code Generation” before. However, the fact that the generated code has to be a program is a problem. Our main goal is to mock subprograms and external subroutines, because most of our dependencies are those module types.

Best regards,
Stefan

OK so back to scratch :frowning:

Regarding you original question 2
I can’t see why you should not be able to use the SHCMD command to start a scripts from inside you program that starts natural batch and compiles a subprog and then does the callnat of the new compiled module.

See the doc of SHCMD - synch is default ie waits for script to end: http://techcommunity.softwareag.com/ecosystem/documentation/natural/nat838unx/pg/pg_furth_syscom.htm?hi=shcmd

Just to get things straight in my head:

You have existing code which does things like CALLNATs and external PERFORMs.

You do not want to modify the existing production code.

You want to create separate versions of the subprograms and external subroutines for testing purposes. Again, the production modules are not to be touched.

There are no “pretty” solutions to the above using Natural.

Some possibilities:

If the production code could be modified, there is a simple approach. Within the production code you could modify a CALLNAT as follows:

IF some-flag
CALLNAT production-B … with appropriate arguments
else
CALLNAT testing-B … with appropriate arguments
END-IF

The problem with this is that all external PERFORMs and CALLNATs would have to be modified. Depending on how many such calls exist, this could be a performance issue, but probably not. You are are only adding an IF test per call. Not a big issue.

The IF tests could reside in external modules. For example, if the external subroutines and subprograms could be modified, the code could be placed there. Or you could have separate modules for each subroutine that would have the IF clause above.

Which brings us to one final approach. How often is the code modified? If the answer is “not very often”, the best solution might be to duplicate the existing production code. In the second copy of the code, add the aforementioned IF statements in the mainline of the code.
Thus, you do not have the extra overhead of the IFs when running production (original copy without IFs).

That’s more or less my current solution. I’m not using SHCMD (which I’ll definitely look into) but a User Exit for calling the shell script. However, the overhead for calling the script and “mocking” via the file system is about 1 second per call. And that would slow down my test suite. I’m thinking of hundreds of tests with these mocks and they have to run fast. So I thought a Natural internal solution would be better than messing with the file system.

Yes, that’s exactly what I want! :smiley:

Changing the production code could introduce bugs, which I don’t want. Also, I don’t want the production modules to “know” that they might be tested and should behave differently in this case. They should not know anything about the mocks. And your solution would also require me to write the mocks up front, which I don’t want. I need the tests to generate and compile the mocks at runtime, because each test might need individual return values from the mocked modules. And if I have to write these mocks as “real” modules, there would be lots of those laying around.

Example: Test a subprogram TOTEST, that adds two numbers, one of which comes from a CALLNAT ‘TOMOCK’.

Module to test:

CALLNAT 'TOMOCK' #SECOND-NUMBER
#MY-PARAM := 5 + #SECOND-NUMBER

Test 1:

/* -> mock TOMOCK to return 3
CALLNAT 'TOTEST' #MY-PARAM
ASSERT-EQUALS 8 #MY-PARAM

Test 2:

/* -> mock TOMOCK to return -3
CALLNAT 'TOTEST' #MY-PARAM
ASSERT-EQUALS 2 #MY-PARAM

For this simple test I would need to create two mock modules each with only a single line of code (returning 3 and -3). And I don’t want this overhead. Instead, these simple modules should be created at runtime and should be disposed right after the test finishes.

I looked into SHCMD and it more or less does the same thing as User Exit USR1052N: Send a command to the operating system. However, USR1052N directly returns the exit code of the shell script and doesn’t require a separate call to RET.

However, I’ll compare the two possibilities and check if one is faster than the other.