You are on page 1of 35

TAFJ-U ni tT e s t F r a m e w o r k

R22
TAFJ-U ni tT e s t F r a m e w o r k

Amendment History:

Revisio
Date Amended Name Description
n
1 Sep 11 2015 T. Aubert Initial version
2 Nov 5 2015 T. Aubert New functionalities added
3 Dec 15 2015 T. Aubert Removed the recording facilities

4 15th March 2016 M. Kumar R16 AMR review

5 April 21st 2016 T. Aubert Add ignoreMissingStubs() description

6 May 2nd 2016 T. Aubert Add reset() description

7 May 6th 2016 T.Aubert Stub Conditions and new modifiers

Add saveContext() and restoreContext() and


8 May 9th 2016 T.Aubert
removeStub(...)

9 May 17th 2016 T.Aubert Code Coverage and new Result view

10 June 6th 2016 T.Aubert setDate() setTime() resetDateTime()

11 June 6th 2016 T.Aubert lockRecord() unlockRecord()

12 June 29th 2016 T.Aubert AssertNotEquals()

13 July 1st 2016 T.Aubert UTF.setStopping()

14 July 6th 2016 T.Aubert Default Date / Time settings

15 Dec 12th 2016 T. Aubert setFilePointer()

16 Aug 10th 2017 T.Aubert mockSYSTEM()

17 21st March 2019 M. Kumar R19 AMR review

18 24th March 2020 Immanuel KJ R20 AMR review

19 12th April 2021 M. Siranjeevi R21 AMR review

20 25th March 2022 Ekata Malik R22 AMR review

Page 2
TAFJ-U ni tT e s t F r a m e w o r k

Ta b l e o f C o n t e n t s
Copyright................................................................................................................................................ 7
Errata and Comments............................................................................................................................ 7
Introduction............................................................................................................................................. 8
TUT Overview......................................................................................................................................... 8
The UTF “Component”........................................................................................................................... 9
Global UTF Methods............................................................................................................................. 11
UTF.setTarget(<subroutine>)........................................................................................11

UTF.setDescription(<a_description>)...........................................................................11

UTF.addParam(<variable_or_value>)...........................................................................11

UTF.setParam(idx, <variable_or_value>).....................................................................11

UTF.setRecord(<table>, <id>, <record>)......................................................................12

UTF.setFilePointer(<filePointer>, <fileName>).............................................................12

UTF.mockSYSTEM(<index>, <value>).........................................................................12

UTF.ignoreMissingStubs()............................................................................................12

UTF.runTest()............................................................................................................... 12

UTF.reset()...................................................................................................................13

UTF.saveContext().......................................................................................................13

UTF.restoreContext()....................................................................................................13

UTF.setDate(dd, mm, yyyy)..........................................................................................13

UTF.setTime(hh, mm, ss).............................................................................................13

UTF.resetDateTime()....................................................................................................14

UTF.lockRecord(<record>)...........................................................................................14

UTF.unlockRecord(<record>).......................................................................................15

Default Date / Time......................................................................................................15

Page 3
TAFJ-U ni tT e s t F r a m e w o r k

Stubs methods.............................................................................................................15

reference = UTF.addStub(<subroutine>)......................................................................15

UTF.removeStub(<a_stub_ref>)...................................................................................16

UTF.setRepeatable(<a_stub_ref>)...............................................................................16

UTF.setStopping(<a_sub_ref>)....................................................................................16

UTF.addStubParam(<a_stub_ref>, <in_value>, <out_value>).....................................16

UTF.addStubCommonChange(<a_stub_ref>,<common>,<out_value>).......................17

UTF.addStubCacheChange(<a_stub_ref>, <bucket_name>, <key>, <out_value>)......17

UTF.addStubWriteDone(<a_stub_ref>,<table>,<id>, <out_record>)............................17

UTF.addStubPropertyChange(<a_stub_ref>,<component>,<property>, <value>).......18

UTF.setStubReturnValue(<a_stub_ref>, <value>)........................................................18

UTF.getNbInvocation(<a_stub_ref>)............................................................................18

Stub Conditions............................................................................................................ 19

IO Method............................................................................................................................................. 19
Assertions methods.............................................................................................................................. 20
UTF.assertEquals(<value1>, <value2>).......................................................................21

UTF.assertNotEquals(<value1>, <value2>)..................................................................21

UTF.assertContains(<value1>, <value2>)....................................................................21

UTF.assertTrue(<value>).............................................................................................21

UTF.assertFalse(<value>)............................................................................................21

UTF.assertGreaterThan(<value1>, <value2>)..............................................................21

UTF.assertLessThan(<value1>, <value2>)..................................................................21

UTF.assertStartsWith(<value1>, <value2>)..................................................................21

UTF.assertEndsWith(<value1>, <value2>)...................................................................21

UTF.assertMatches(<value1>, <mask>).......................................................................21

UTF.getRecord(<table>, <id>)......................................................................................22

Page 4
TAFJ-U ni tT e s t F r a m e w o r k

Modifiers............................................................................................................................................... 22
UTF.any()..................................................................................................................... 23

UTF.matches(<mask>).................................................................................................23

UTF.same().................................................................................................................. 23

UTF.isTrue(<value>).....................................................................................................24

UTF.isFalse(<value>)...................................................................................................24

UTF.contains(<value>).................................................................................................24

UTF.endsWith(<value>)...............................................................................................24

UTF.startsWith(<value>)..............................................................................................24

UTF.greaterThan(<value>)...........................................................................................24

UTF.lessThan(<value>)................................................................................................24

Creating a new UnitTest....................................................................................................................... 25


From scratch................................................................................................................25

Editor Helpers..............................................................................................................27

Setting the target..........................................................................................................27

Adding a stub............................................................................................................... 28

JBC Subroutine selection dialog..................................................................................28

Converting old tuts................................................................................................................................ 30


Compiling, and distributing tests..................................................................................30

Running tests........................................................................................................................................ 30
In console mode...........................................................................................................30

Running multiple tests at once.....................................................................................31

Return value................................................................................................................. 31

In Eclipse..................................................................................................................... 32

The “result” view...........................................................................................................33

Colors meaning............................................................................................................ 34

Page 5
TAFJ-U ni tT e s t F r a m e w o r k

Reporting.............................................................................................................................................. 35
Component and UnitTests.................................................................................................................... 35
Scoping exception........................................................................................................35

Stubbing a method.......................................................................................................35

Page 6
TAFJ-U ni tT e s t F r a m e w o r k

C o pyri g h t
Copyright © Temenos Headquarters SA 2009-2022. All rights reserved.
This document contains proprietary information that is protected by copyright. No part of this document may
be reproduced, transmitted, or made available directly or indirectly to a third party without the express
written agreement of TEMENOS UK Limited. Receipt of this material directly TEMENOS UK Limited
constitutes its express permission to copy. Permission to use or copy this document expressly excludes
modifying it for any purpose, or using it to create a derivative therefrom.

Err a t a a n d C o m m e n t s
If you have any comments regarding this manual or wish to report any errors in the
documentation, please document them and send them to the address below:
Technology Department

Temenos Headquarters SA
2 Rue de l’Ecole-de-Chimie,
CH - 1205 Geneva,
Switzerland

Tel SB: +41 (0) 22 708 1150


Fax: +41 (0) 22 708 1160

Please include your name, company, address, and telephone and fax numbers, and email
address if applicable. TAFJdev@temenos.com

Page 7
TAFJ-U ni tT e s t F r a m e w o r k

Intr o d u c ti o n
The Unit Test Framework (UTF) helps developers and testers to validate that the code is
doing what it is intended to do. The version 1.0 was storing binary informations, and was
requiring a specific editor to modify a tests. Despite that the “binary” way of storing in
formations was a good approach for huge sets of informations, the downsides were too big,
and a full re-engineering has been done to get to the Version 2.
The Version 2 still have the recording facility, and this is much easier to maintain the test as
this ends up being “just” jBC code. However, unlike EasyQA, there is only one file per test
and the full Eclipse launching facilities are still available. This document aims to describe in
details how this all work. You will notice that there is no “deployment” section as everything is
embedded in the existing runtime / compiler / eclipse plugins.

T UT Ov e rvi e w
A .tut file is a jBC file. However, the extension .tut is necessary to help the different tools to
discover the tests.
A tut is not a SUBROUTINE, neither a PROGRAM nor a FUNCTION. This is a
“TESTCASE”.
So every tuts are starting with TESTCASE <name of test> as shown here :

We could wonder why this could not be a simple SUBROUTINE or PROGRAM, and later in
the document, everything will make sense. For now, we simply need to know that a UnitTest
is declared in the code with TESTCASE.
Then, this is just jBC, anything jBC can do can be done in a tut. However, this would not be
really useful to stop at that point, and this is here that the TESTCASE declaration starts to
make sense. In fact, by using TESTCASE, this will automatically add a low-level reference in
the code. This reference is “UTF”. IN the next chapter, we will describe all the methods the
UTF reference (object) is offering. We will call it a “component” to make the reading more jBC
oriented, but in fact this is a real Object.

Page 8
TAFJ-U ni tT e s t F r a m e w o r k

T h e U T F “C o m p o n e n t ”

So we know now that a Temenos Unit Test is a file with the “tut” extension that this is written
in jBC and that the declaration is “TESTCASE” because we need the “UTF Component”
which will help us doing a test. So let's look in details at this Component.

First, this is a low-level component, sitting into the runtime, so don't try to find something like
UTF.component on your disk, it doesn't exists. Then, this component is automatically “here”.
No need to do a $USING or whatsoever, it sits behind your code. You can consider it as a
language extension. Let's explore all these extensions. The full list :
Global methods :

UTF.runTest()

UTF.setTarget(<subroutine>)

UTF.setDescription(<a_description>)

UTF.addParam(<variable_or_value>)

UTF.setRecord(<table>, <id>, <record>)

UTF.ignoreMissingStubs()

UTF.mockSYSTEM(<index>, <value>)

UTF.runTest()

Stubs methods :

UTF.addStub(<subroutine>)

UTF.setRepeatable(<a_stub_ref>)

UTF.addStubParam(<a_stub_ref>, <in_value>, <out_value>)

UTF.addStubCommonChange(<a_stub_ref>, <common>, <out_value>)

UTF.addStubCacheChange(<a_stub_ref>, <bucket_name>, <key>,


<out_value>)

UTF.addStubWriteDone(<a_stub_ref>, <table>, <id>, <out_record>)

UTF.addStubPropertyChange(<a_stub_ref>, <component>, <property>,


<value>)

Page 9
TAFJ-U ni tT e s t F r a m e w o r k

UTF.setStubReturnValue(<a_stub_ref>, <value>)

Assertions methods :

UTF.assertEquals(<value1>, <value2>)

UTF.assertContains(<value1>, <value2>)

UTF.assertTrue(<value>)

UTF.assertFalse(<value>)

UTF.assertGreaterThan(<value1>, <value2>)

UTF.assertLessThan(<value1>, <value2>)

UTF.assertStartsWith(<value1>, <value2>)

UTF.assertEndsWith(<value1>, <value2>)

UTF.assertMatches(<value1>, <mask>)

UTF.getRecord(<table>, <id>)

Modifiers methods :

UTF.any()

UTF.matches(<mask>)

UTF.same()

Page 10
TAFJ-U ni tT e s t F r a m e w o r k

Gl o b a l U T F M e t h o d s
U TF. s e tT ar g e t ( < s u b r o u t i n e > )
Usually the very first method (but not mandatory), this is defining what subroutine we want to
test. This subroutine will be called with the UTF.runTest() method described later.

You can pass a variable as well as a constant value.

XYZ = "TEST.SIMPLE"

UTF.setTarget(XYZ)

or

UTF.setTarget("TEST.SIMPLE")

Note that this will be always the same for all parameter, so we won't repeat it.

U TF. s e t D e s c r i p t i o n ( < a_ d e s c r i p t i o n > )


This is setting a description for the test (for reporting purposes)

U TF. a d d P a r a m ( < v a r i a b l e_ or_v al u e > )


This one needs to be called as many times as you have parameters in your target. Here, you
should (but not mandatory) put a variable, because this is what you will reference in the
assertions. (see later)

Here are two examples :

P1 = "7"

UTF.addParam(P1)

DIM P2(10)

P2(2) = "6"

UTF.addParam(P2)

U TF. s e t P a r a m ( i d x , < v a r i a b l e_ or_v a l u e > )


This is possible to modify (in oposition to add) a parameter. In that case, you will use the
setParam() instead of the addParam.

Eg :

P1 = "10"

UTF.setParam(1, P1)

Page 11
TAFJ-U ni tT e s t F r a m e w o r k

U TF. s e t R e c o r d ( < t a b l e > , < i d > , < r e c o r d > )


Since running the test is not touching at the database, if your test is dependent of a pre-
existing record, you must add this record with this method. This is a little bit as if you where
writing a record in a database, but this is kept in memory.

UTF.setRecord("F.MY.TEST", "MY.KEY.1", 'Field1' : @FM : "Field2")

This function return a record pointer which can be used in lock / unlock Record (see
lockRecord(), unlockRecord()). So you can write :

myRecord = UTF.setRecord("F.MY.TEST", "MY.KEY.1", 'value')

U TF. s e t F i l e P o i n t e r ( < f i l e P o i n t e r > , < f i l e N a m e > )


There are some cases where the filepointer (eg used in a READ) is a COMMON variable and
there is no OPEN (OPF) done during the process. So in that case, we can directly set the
filepointer to the corresponding variable like this :

UTF.setFilePointer(F$AA.ARRANGEMENT, "F.AA.ARRANGEMENT")

U TF. m o c k SY S TE M ( < i n d e x > , < v a l u e > )


Mock any SYSTEM() variables. Eg, to make believe the target routine that a transaction is
started, you can write something like this

UTF.mockSYSTEM(47, @TRUE)

Later, if the target routine does something like this


 IF SYSTEM(47) THEN …

This will be true

Note : Mocked system variables are cleared on a reset().

U TF.i g n o r e M i s s i n g S t u b s ( )
This method informs the UTF that is a stub is missing, it will be simply ignored and no error
will be raised. This is to use with caution as this becomes difficult to debug the target. Useful
for huge routines for which we only want to test a small portion.

U TF.r u nT e s t ( )
This method simply launch the test (call the routine defined by the setTarget(...). This method
must be called after the stubs definition (see next section)

Page 12
TAFJ-U ni tT e s t F r a m e w o r k

If the routine defined by the setTarget is a FUNCTION, then UTF.runTest() will return the
value of the function.

Eg :

ret.value = UTF.runTest()

U TF.r e s e t ( )
Clear completelly the context (COMMON, properties, records, static cache, mocked
SYSTEM and parameters).

U TF. s a v e C o n t e x t ( )
Save (in-memory) a snapshot of the current COMMON, properties, records, static cache and
parameters.

U TF.r e s t o r e C o n t e x t ( )
Restore the previously saved context (see saveContext()). This is also setting all the stubs
invocation counter back to 0.

U TF. s e t D a t e ( d d , m m , yyyy )
Allow the test to set the date. This affects functions like DATE(), TIMEDATE(), TIMESTAMP(),
SYSTEM(12). The time is not modified. Note that the timezone is irrelevant. Note : look also
at the “Default Date / Time” chapter.

U TF. s e t Ti m e ( h h , m m , s s )
Allow the test to set the time. This affects functions like TIME(), TIMEDATE(), TIMESTAMP(),
SYSTEM(12). The date is not modified. Note that the timezone is irrelevant. Note : look also
at the “Default Date / Time” chapter.

Typically, this type of test will give the same result wherever you run it on the planet :

SUBROUTINE TEST.DATE.TIME(date, time, timedate, timestamp, sys12)


date = DATE()
time = TIME()
timedate = TIMEDATE()
timestamp = TIMESTAMP()
sys12 = SYSTEM(12)
END

TESTCASE TestDATE.TIME
UTF.setTarget("TEST.DATE.TIME")
date = ''
UTF.addParam(date)
time = ''
UTF.addParam(time)
timedate = ''

Page 13
TAFJ-U ni tT e s t F r a m e w o r k

UTF.addParam(timedate)
timestamp = ''
UTF.addParam(timestamp)
sys12 = ''
UTF.addParam(sys12)

UTF.setDate(26, 04, 1968)


UTF.setTime(03, 14, 15)

UTF.runTest()

UTF.assertEquals(date, 117)
UTF.assertEquals(time, 11655)
UTF.assertEquals(timedate, "03:14:15 26 APR 1968")
UTF.assertEquals(timestamp, -53127945)
UTF.assertEquals(sys12, 11655000)
END

U TF.r e s e t D a t e T i m e ( )
Reset (cancel any setDate() or setTime()) the date / time to the current / default one.

U TF.l o c k R e c o r d ( < r e c o r d > )


In some specific circumstances, you may want to test a situation where a record is locked. You can
do that by putting the lock flag on a record using the lockRecord() function. The parameter passed
is the return value of the setRecord() method.

Example :
myRecord = UTF.setRecord("FBNK.CURRENCY", "USD", "This is a CCY Record")
UTF.lockRecord(myRecord)

This will affect READU, CALL F.READU(), MATREADU, CALL F.MATREADU() and READVU

Here is a full code showing a routine and its test :


SUBROUTINE GET.LOCK(REC)
OPEN "FBNK.CURRENCY" TO F.FILE ELSE NULL
DIM AR(100)
MATREADU AR FROM F.FILE, "USD" LOCKED
REC = "MATREADU RECORD LOCKED / "
END
READU R FROM F.FILE, "USD" LOCKED
REC := "READU RECORD LOCKED / "
END
READVU R FROM F.FILE, "USD", 2 LOCKED
REC := "READVU RECORD LOCKED / "
END
ER = ""
CALL F.MATREADU ("FBNK.CURRENCY","USD",MAT AR,100,F.FILEID,ER,RETRY)

Page 14
TAFJ-U ni tT e s t F r a m e w o r k

REC = REC : ER : " / "


ER = ""
CALL F.READU ("FBNK.CURRENCY","USD",REC2,F.FILEID,ER,RETRY)
REC = REC : ER
END

TESTCASE TestGET.LOCK
UTF.setTarget("GET.LOCK")
REC = ''
UTF.addParam(REC)
myRecord = UTF.setRecord("FBNK.CURRENCY", "USD", "Currency Record")
UTF.lockRecord(myRecord)
UTF.runTest()
UTF.assertEquals(REC, "MATREADU RECORD LOCKED / READU RECORD LOCKED / READVU
RECORD LOCKED / RECORD LOCKED / RECORD LOCKED")
END

U TF. u n l o c k R e c o r d ( < r e c o r d > )


Unlock a record. See UTF.lockRecord()

D e f a u l t D a t e / Ti m e
In addition to the setDate() / setTime() method which are done for individual testcase, you
can change your environment date and time by setting the properties (in your
<project>.properties file) like this :

temn.tafj.utf.default.date = “dd/mm/yyyy”

temn.tafj.utf.default.time = “hh:mm:ss”

Note that the format is important and must match exactly the pattern described. As an
example, “26/04/68” is invalid !

Stubs m ethods

r e f e r e n c e = U TF. a d d S t u b ( < s u b r o u t i n e > )


This is the declaring method for a stub (the replacement of a routine). Imagine your target is
calling the subroutine DO.SOMETHING, then you will declare it like this :

STUB = UTF.addStub("DO.SOMETHING")

Note that the return value is a function. You cannot do a lot with it appart passing it back to
the next stub related functions.

Page 15
TAFJ-U ni tT e s t F r a m e w o r k

U TF.r e m o v e S t u b ( < a_ s t u b_r e f > )


Remove (delete) an existing stub

U TF. s e t R e p e a t a b l e ( < a_ s t u b_r e f > )


Normally, when the invocation of a sub is done, this one will not be re-used. As an example, if
the target is calling 2 times DO.SOMETHING, then you should have 2 stubs (you should put
2 UTF.addStub(“DO.SOMETHING”). However, by specifying that the stub is repeatable, this
save you to declare it twice. A typical routine in T24 which can be “repeatable” is “CDT”.

The section describing how the stubs are found (later in this document) will certainly bring
some lights.

U TF. s e t S t o p p i n g ( < a_ s u b_r e f > )


In some circumstances, a subroutine is issuing a STOP statement (like FATAL.ERROR in
T24). In that case, you can specify it for your stub like this :

STUB = UTF.addStub("FATAL.ERROR")
UTF.addStubParam(STUB, UTF.any(), UTF.same())
UTF.setStopping(STUB)

U TF. a d d S t u b P a r a m ( < a_ s t u b_r e f > , < i n_v a l u e > , < o u t_v a l u e > )
This method has to be invoked as many times as the number of parameters in your stub. In
DO.SOMETHING, we have 3 parameters, so we need to invoke 3 times
UTF.addStubParam(...). The first parameter is the stub references (obtained when doing
UTF.addStub), the second one is the in-parameter, the third one is the value of this
parameter after the call. We could argue about the in-parameter need. This one is used to
detect which stub needs to be called. If we take the same CDT function, we will have

STUB = UTF.addStub("CDT")
UTF.addStubParam(STUB, '', '')
UTF.addStubParam(STUB, "20130623", "20130624")
UTF.addStubParam(STUB, "+1C", "+1C")

STUB = UTF.addStub("CDT")
UTF.addStubParam(STUB, '', '')
UTF.addStubParam(STUB, "20130523", "20130524")
UTF.addStubParam(STUB, "+1C", "+1C")

When the target calls CDT('', 20130623, “+1C”), then the 2nd parameter changes to
20130624. The tests needs to know which one to take. This explain the in-parameter.

Note that STUB is just a variable name, you can put anything you want.

Page 16
TAFJ-U ni tT e s t F r a m e w o r k

MY.FIRST.STUB = UTF.addStub("CDT")

UTF.addStubParam(MY.FIRST.STUB, '', '')

. . .

U TF. a d d S t u b C o m m o n C h a n g e ( < a_ s t u b_r e f > , < c o m m o n > , < o u t_v a l u e


>)
Here, this is how we say that the subroutine is supposed to change the value of a common
variable. Remember, since the routine is never really called, we need to tell everything. Of
course, only common variable having an impact on the target routine are necessary.

UTF.addStubCommonChange(STUB, COMI, "A NEW VALUE FOR COMI")

If your common is an DIMmed array (eg R.NEW), you will pass an array as new value :

DIM stubCommon(500)

stubCommon(10) = "A New Value for R.NEW"

UTF.addStubCommonChange(STUB, R.NEW, stubCommon)

U TF. a d d S t u b C a c h e C h a n g e ( < a_ s t u b_r e f > , < b u c k e t_ n a m e > , < k ey >,


< o u t_v a l u e > )
Same approach as for the common, appart from the fact that you are not passing the
common itself, but the Bucket name and the key.

Doing something like that :

UTF.addStubCacheChange(STUB, "USED.BUCKET", "KEY1", "A New Value")

Is the equivalent as the real routine doing

CachePut("USED.BUCKET", "KEY1", "A New Value")

Page 17
TAFJ-U ni tT e s t F r a m e w o r k

U TF. a d d S t u b Wri t e D o n e ( < a_ s t u b_r e f > , < t a b l e > , < i d > , < o u t_r e c o r d > )
Exactly the same as the previous one, but for database.

So doing

UTF.addStubWriteDone(STUB, "F.MY.TEST", "MY.KEY.1", "A new Record")

is the same as if the routine were doing a F.WRITE. Of course, the database is not touched,
but this is “as if ...”

So after the stub invocation, the target routine can do a

CALL F.READ("F.MY.TEST", "MY.KEY.1", REC, F.MY.TEST, ERR)

In REC, we would find : "A new Record"

U TF. a d d S t u b P r o p e r t yC h a n g e ( < a_ s t u b_r e f > , < c o m p o n e n t > , < p r o p


erty >, < v al u e > )
When using components, COMMON variables are not accessible directly. Instead, these are
getters / setters on a property defined n the component. Use the addStubPropertyChange
method, giving the component name and it's property for changing it when the stub is
invoked.

As an example, if a routine was doing

MOD.MyComponent.setMyProperty('a new value')

you will tell the stub the following :

UTF.addStubPropertyChange(STUB, 'MOD.MyComponent', 'MyProperty', 'a new value')

U TF. s e t S t u b R e t u r nV al u e ( < a_ s t u b_r e f > , < v a l u e > )


If a stubb is a function, you will specify the return value of the function with this method

Page 18
TAFJ-U ni tT e s t F r a m e w o r k

U TF. g e t N b I n v o c a t i o n ( < a_ s t u b_r e f > )

Return the number of time a stub got invoked during the test
example (check that our stub got invoked 2 times) :

NB.STUB = UTF.getNbInvocation(STUB)

UTF.assertEquals(2, NB.STUB)

St u b Conditio n s
The way stubs are selected is, by nature, based on parameters. These parameters can have
modifiers (see specific chapter) or can be set as UTF.any(). However, this is sometimes
necessary to specify when a STUB is eligible based on COMMON variables or Properties.

There are 2 methods to create such conditions :

UTF.addStubCommonCondition(<a_stub_ref>, A.COMMON, value)


eg :
UTF.addStubCommonCondition(STUB, COMI, “1234”)
or
UTF.addStubPropertyCondition(<a_stub_ref>, “Component.name”, “Property”, value)
eg :
UTF.addStubPropertyCondition(STUB, “EB.SystemTables”, “Comi”, “1234”)
The value can be wrapped by all the modifiers.
Eg :
UTF.addStubCommonCondition(STUB, COMI, UTF.lessThan(1234))
Which means :

This STUB is valid if the COMMON variable COMI is less than 1234 at the moment of the
call.

IO M e t h o d
IO Keywords (OPEN, READ, WRITE, DELETE, MATREAD, MATWRITE, OPENSEQ,
READSEQ, WRITESEQ) but also their corresponding methods (F.READ, CACHE.READ,
F.WRITE, F.MATWRITE, F.MATREAD, F.DELETE) are all based on a “in-memory storage).

There is no need to STUB a F.READ, neither a F.WRITE, .... They will automatically
use/update this in-mem storage.

Page 19
TAFJ-U ni tT e s t F r a m e w o r k

Now, before running a test (runTest()), you will use the UTF.setRecord() method, and after
the test, if you want to verify a record, you will used the UTF.getRecord() method.

In the case of the SEQuencial files, you will use the exact same mechanism, but the ID will
have to stay empty (“”).

Here is an example of SEQUENCIAL access :

The Target :

SUBROUTINE DO.SEQ(FIRSTLINE)
OPENSEQ "/home/user/TOTEST", "MY.FILE" TO F.SEQ.FILE THEN
READSEQ FIRSTLINE FROM F.SEQ.FILE ELSE NULL
WRITESEQ "One Value" ON F.SEQ.FILE THEN NULL
WRITESEQ "Another Value" ON F.SEQ.FILE THEN NULL
END
END
END

The test :

TESTCASE TestDO.SEQ
UTF.setTarget("DO.SEQ")
PARAM = ""
UTF.addParam(PARAM)
NL = CHAR(10)
* Add a line in this in-mem file
MY.REC="Line 1" : NL
UTF.setRecord("MY.FILE", "", MY.REC)
UTF.runTest("Test SEQ")
UTF.assertEquals(PARAM, "Line 1")
* Get the record and verify that the writeseq occurred.
REC = UTF.getRecord("MY.FILE", "")
UTF.assertEquals(REC, "Line 1":NL:"One Value":NL:"Another Value":NL)
END

Ass ertio n s m e t h o d s

These methods are obvious and talking by themselves. If one of these method is evaluated
as “false”, the test will be in “failure”. Please refer to the “reporting” and “eclipse” chapters for
more details.

One small note on the parameters.

Page 20
TAFJ-U ni tT e s t F r a m e w o r k

At the beginning of the document, we mentioned that the parameters should be put as
variables and not constant. Imagine that you wrote

UTF.addParam("7")

Instead of

P1 = "7"

UTF.addParam(P1)

This would make no sense to make an assertion on “7” : UTF.assertEquals("7", "7")

But verifying that the first parameter is not changing :

UTF.assertEquals(P1, "7")

Makes suddenly more sense.

U TF. a s s e r t E q u a l s ( < v a l u e 1 > , < v a l u e 2 > )


TRUE if <value1> is equals to <value2>, FALSE otherwise

U TF. a s s e r t N o t E q u a l s ( < v a l u e 1 > , < v a l u e 2 > )


TRUE if <value1> is different than<value2>, FALSE otherwise

U TF. a s s e r tC o n t a i n s ( < v a l u e 1 > , < v a l u e 2 > )


TRUE if <value1> contains <value2>, FALSE otherwise

U TF. a s s e r tTr u e ( < v a l u e > )


TRUE if <value1> is evaluated (jBC) to TRUE (same as IF <value1> ...)

U TF. a s s e r tF a l s e ( < v a l u e > )


TRUE if <value1> is evaluated (jBC) to FALSE (same as IF NOT(<value1>) ...)

Page 21
TAFJ-U ni tT e s t F r a m e w o r k

U TF. a s s e r tGr e a t e rT h a n ( < v a l u e 1 > , < v a l u e 2 > )


TRUE if <value1> GT <value2>, FALSE otherwise

U TF. a s s e r tL e s s T h a n ( < v a l u e 1 > , < v a l u e 2 > )


TRUE if <value1> LT <value2>, FALSE otherwise

U TF. a s s e r t S t a r t s W i t h ( < v a l u e 1 > , < v a l u e 2 > )


TRUE if <value1> Starts With <value2>, FALSE otherwise

U TF. a s s e r t E n d s W i t h ( < v a l u e 1 > , < v a l u e 2 > )


TRUE if <value1> Ends With <value2>, FALSE otherwise

U TF. a s s e r t M a t c h e s ( < v a l u e 1 > , < m a s k > )


TRUE if <value1> MATCHES <value2>, FALSE otherwise

This is the MATCH equivalent of jBC

eg

UTF.assertMatches(P1, "3N4X")

P1 = "123ABCD" : TRUE

P1 = "123ABC" : FALSE

U TF. g e t R e c o r d ( < t a b l e > , < i d > )


This is fetching a record from the (in-memory database) useful for making assertions on the
record.

REC = UTF.getRecord("F.MY.TEST", "MY.KEY.2")

UTF.assertEquals(REC, 'A new Record from stub' : @FM : "Modified")

M o difi er s
This section should in fact be linked to the Stubs, but for clarity of the documents let's keep it
at the end. Modifiers are informations you can pass as arguments to the stub definitions or
the stubs conditions.

Page 22
TAFJ-U ni tT e s t F r a m e w o r k

When a test is running, and the target is making a CALL, the UTF is looking for the best
matching stub. The first absolute test is the stub name (the SUBROUTINE name must match
EXACTELY the call -obvious-). Then, we will check the parameters.

If all the parameters are “normally” defined, then they must match exactly as well, however,
we can put modifiers so the stub could not fully match.

Example :

UTF.addStubParam(STUB, UTF.any(), "Anything")

Means that whatever the in parameter is, this stub will be eligible for the CALL and the
parameter will be changed to "Anything"

UTF.addStubParam(STUB, UTF.matches("2N"), "less than hundred")

Means that if the in parameter Matches "2N", this stub will be eligible for the CALL and the
parameter will be changed to "less than hundred"

So what if we have multiple stubs being eligible ?

The rules is the following.

The stubs are sorted by <number of strict value>, <number of match value> and <number of
“any” value>. The top most stub will be taken.

In the precedent example, UTF.matches("2N") is better than UTF.any(). However, if we


had UTF.addStubParam(STUB, "12", "twelve"), and the parameter was "12", this is the
one which would have been taken.

U TF. a n y ( )
Do not consider the parameter to elect the stub as a good stub for a given CALL.

U TF. m a t c h e s ( < m a s k > )


Elect the stub as a good stub for a given CALL if the parameter is matching (jBC MATCH) the
given mask.

Page 23
TAFJ-U ni tT e s t F r a m e w o r k

U TF. s a m e ( )
UTF.same() is not a modifier as such. It is defined for the out-parameter. This is basically
saying that the out parameter ends up having the same value as the in. As an example, this
parameter :

UTF.addStubParam(STUB, UTF.matches("2N"), UTF.same())

Would not change the parameter if this is a 2 digit number, and of course, if there is no better
match (eg UTF.addStubParam(STUB, "12", "twelve"))

The following modifiers do obviously not need any explanations :

U TF.i sTr u e ( < v a l u e > )

U TF.i sF a l s e ( < v a l u e > )

U TF. c o n t a i n s ( < v a l u e > )

U TF. e n d s W i t h ( < v a l u e > )

U TF. s t a r t s W i t h ( < v a l u e > )

U TF. g r e a t e r T h a n ( < v a l u e > )

U TF.l e s s T h a n ( < v a l u e > )

Remember that they can be used with

- UTF.addStubParam

- UTF.addStubCommonCondition

- UTF. addStubPropertyCondition

Page 24
TAFJ-U ni tT e s t F r a m e w o r k

Cr e a t i n g a n e w U n i tT e s t

Fr o m s c r a t c h
Creating a test is not any different than creating a new SUBROUTINE : In Eclipse, Right-click
on the directory where you want to create your test, select

New - > T24 routine / component / testcase

Select “Create UnitTest”, give a name to your file …

Page 25
TAFJ-U ni tT e s t F r a m e w o r k

And automatically a new TestCase, with a template will be created as follows :

Then this is just a matter to edit / save / run.

Page 26
TAFJ-U ni tT e s t F r a m e w o r k

Edit or H elp er s
When editing a TESTCASE, you have some options in the contextual menu of your editor.
Righ-click on the editor (where you want to add something). You will have the “Unit Test
Framework ….” menu available with 2 options : “Setting the target...” and “Adding a stub...”

S e tti n g t h e tar g e t
This option will open the JBC Subroutine selection dialog (see specific chapter).

Select a routine or component method, and the code for setting the target with all parameters
will be added. You only will need to specify the values of the parameters.

Example by choosing AA.Fees.CalculateTierAmount(...) :

UTF.setTarget("AA.Fees.CalculateTierAmount")

TierGroup = ''

UTF.addParam(TierGroup)

TierType = ''

UTF.addParam(TierType)

. . .

ChargeCalcDetails = ''

UTF.addParam(ChargeCalcDetails)

RetError = ''

UTF.addParam(RetError)

You just need to specify values to your variables.

Page 27
TAFJ-U ni tT e s t F r a m e w o r k

Ad d i n g a s t u b
Adding a stub is done the same way as setting the target. The code will be generated like
this ( for AC.API.EbUpdateAcctEntFwd )

STUB = UTF.addStub("AC.API.EbUpdateAcctEntFwd")

UTF.addStubParam(STUB, UTF.any(), UTF.same()) ;* AccountId

UTF.addStubParam(STUB, UTF.any(), UTF.same()) ;* Action

UTF.addStubParam(STUB, UTF.any(), UTF.same()) ;* EntryId

UTF.addStubParam(STUB, UTF.any(), UTF.same()) ;* ErrorCode

The default values are UTF.any() for the IN param and UTF.same() for the OUT param. You
will need to change these values according to your test case.

JBC S u b r o u t i n e s e l e c t i o n d i a l o g

The precedent chapter is mentioning this dialog box, and here is a description of how it
works.

Page 28
TAFJ-U ni tT e s t F r a m e w o r k

IMPORTANT : The contents of this dialog box IS NOT THE SOURCE files, but the
compiled one. This means you don't need to have all sources to be able to select a
routine. Just have the jars in your precompile directory.

Page 29
TAFJ-U ni tT e s t F r a m e w o r k

Co nv ertin g old t ut s

There is a tool to convert tut version 1.0 to the new 2.0 version.
In the TAFJ/bin directory, you will find the tConvertTest (.bat file).
The syntax is :

tConvertTest <file_to_convert> [<new_file>]

If the new file is omitted, the <file_to_convert> will be overridden by the new one.

Co m pili n g, a n d di strib uti n g t e s t s

A test acts as a jBC PROGRAM or SUBROUTINE. There compile the same way, a Class is
generated, this class can be put in a jar.

Running tests
In c o n s ol e m o d e

Running a test is not very different as running a program. There is only one flag to specify : “-
test”. This flag is necessary as the class generated is prefixed with “testcase.” to not conflict
with the target subroutine.

To resume :

MY.SUBROUTINE.b generate a class called MY_SUBROUTINE_cl.class

MY.SUBROUTINE.tut generate a class called testcase_MY_SUBROUTINE_cl.class

example : tRun MY.SUBROUTINE will try to run the class MY_SUBROUTINE_cl.class which
is wrong. You have to run :

tRun -test MY.SUBROUTINE in order to run testcase_MY_SUBROUTINE_cl.class.

So this is

tRun -test myTest

Page 30
TAFJ-U ni tT e s t F r a m e w o r k

Where “myTest” is the name you gave here :

TESTCASE myTest

You can also run your test by specifying the full file name.

Example :

tRun -test /path/to/my/top/dev/directory/unitTests/myTest.tut

Run ni n g m ultiple t e st s at o n c e

You can also specify a directory. In that case, all tests in this directory will be run

Example :

tRun -test /path/to/my/top/dev/directory/unittests

And last but not least, you can use the -recurs flag if you want to find tests resursively in a
directory and run them :

Example :

tRun -test -recurs /path/to/my/top/dev/directory

R et ur n valu e

In console mode, the exit value of tRun will be 1 if one or more test are failing. A success
value is 0.

Note that a failure can be something else than a wrong assertion. It can be a call to a non
existing routine, a test without assertion, or any kind of technical failure.

Page 31
TAFJ-U ni tT e s t F r a m e w o r k

In Eclip s e
Running a test in eclipse consist of selecting

1) One *.tut file

2) Multiple *.tut files

3) One or multiple directories (containing “at least” one tut file)


Right-Click - > Run (or Debug) As … - > Unit Tests

Automatically, a new window will open showing the tests and their results :

Page 32
TAFJ-U ni tT e s t F r a m e w o r k

T h e “r e s u l t” vi e w

This view will show all possible informations regarding the different tests.

One *.tut file can contains multiple tests (UTF.runTest(..). In that case, this single tut file will
be presented as multiple test, with a counter (2nd column). You can drill-down (open) the line
to see the different assertions.

Also, the last column is showing the code coverage of the target. You can right-click on a line
and you will have the choice to

1) open the tut file

2) open the target with the code coverage highlights (or double click)

3) open the target.

Also, by double-clicking on an assertion, the tut file will be open and the focus will be given to
the assertion line.

Page 33
TAFJ-U ni tT e s t F r a m e w o r k

Color s m e a ni n g

Everything which is Green concerns the test itself. If this is a “light” green, this means that
these are lines covered by this test only. The number of line is folowing the percentage. (eg :
53% +2 means : Code coverage of this test is 53 %, and 2 lines are covered just by this test).
This allow the developer to quickly see what is the benefit of this test in term of code

coverage.

The gray lines are lines covered by the other tests for the same target.

The color scheme in the Result view is the same as the one in the editor.

Here is an example of what you will see when double-clicking on a test (not an assertion) or
by choosing “Open Target with Code Coverage”

Line 32 - > 40 are not touched by this test, but are touched by some other tests

Line 17 → 26 are covered by this test and some other tests.

Line 27 /28 are touched by this test and this is the only test touching them.

Page 34
TAFJ-U ni tT e s t F r a m e w o r k

You will see that some lines (29, 36, 38) are not highlighted. This is because there is no
equivalent of these lines in java, and the runtime is never touching them. The count of total
line knows that and the coverage ratio of this target is 100%. This will be resolved in future
versions.

R e p orti n g
You can generate junit types of reports by specifying it in the properties file with the following
keys :
temn.tafj.utf.generate.results = true

By default, the reports (xml files) are generated in

<tafj_home>/data/<projectName>/testResults/

You can change this default location with the key

temn.tafj.utf.results.directory = …

C o m p o n e n t a n d U n i tT e s t s

Sc opin g exc eption


You can use $USING / $PACKAGE as any other jBC file. A small distinguishing : The scoping
do not apply when writing a TESTCASE. This means you can access private methods of any
component.

Stubbin g a m et hod
A method can be stubbed by giving it fully qualified name

UTF.addStub(“MOD.Component.myMethod”)

You do not need to explicitly add a $USING for this stub case.

Page 35

You might also like