Lucky based on gender

One of the situations that makes a person lucky is when that person’s sex is different from previous 5 people. Even though our predetermined inputs cover this case, this criteria comes with implied conditions that:

  • if less than 5 previous persons are of the opposite sex then the current person is not lucky

  • if more than 5 previous persons are of the opposite sex then the current person is lucky

Covering every possible case that is implied by above conditions by using predetermined input is not only not practical but also defeats the purpose of using TorXakis for Model Based Testing. We should make TorXakis test these situations while still generating test data randomly. We can do it by using a Test Purpose that only enforces the sex of generated Person data and leaves the rest to be generated by TorXakis.

Let’s create a PurposeLuckyByGender.txs file and define the process and the Test Purpose in it.

The process

Here is such a Process Definition that can be used for this purpose:

PROCDEF repeatAndSwitchGender [ In :: Person ; Out :: Bool ] ( pos, length :: Int; s :: Sex) HIT ::=
        (
            [[ pos > 1 ]] =>> In ? p [[ sex(p) == s ]] >-> EXIT
            ##
            [[ pos == 1 ]] =>> In ? p [[ (sex(p) == s)
                                        /\ ( not (isLuckyByName(p)))
                                        /\ ( not (isLuckyByBirthday(p)))
                                      ]] >-> EXIT
        )
        >>> Out ? b
        >-> (
                [[pos == length ]] =>> (
                                         [[ isMale(s) ]] =>> repeatAndSwitchGender [In,Out] (1, length, Female)
                                       ##
                                         [[ isFemale(s) ]] =>> repeatAndSwitchGender [In,Out] (1, length+1, Male)
                                       )
                ##
                [[pos < length ]] =>> repeatAndSwitchGender [In, Out] (pos+1,length, s)
            )
ENDDEF

Let’s walk through this Process Definition step by step.

First block in paranthesis **(...)** enforces the criteria on the person data that is communicated through In channel:

(
    [[ pos > 1 ]] =>> In ? p [[ sex(p) == s ]] >-> EXIT
    ##
    [[ pos == 1 ]] =>> In ? p [[ (sex(p) == s)
                                /\ ( not (isLuckyByName(p)))
                                /\ ( not (isLuckyByBirthday(p)))
                              ]] >-> EXIT
)

If current person is not the first person of current gender (position counter is greater than 1) then we just enforce that its gender is the sex that is passed in as parameter.

If current person is the first person of current gender (position counter is 1) then we enforce not only that its gender is the sex that is passed in as parameter, but also that this person is not lucky based on other criteria. Because, with this purpose, we want to observe whether the current person is going to be deemed lucky based on the number of people who came before consecutively with opposite sex. E.g. if a Female comes after 6 consecutive Males and is evaluated to be lucky, we want to be sure that it is because of her gender and not her name or birthday.

##” is the Choice Operator. It means that either one of those processes are executed, but never both.

EXIT” keywords at the end of both processes are needed to signal exiting the block defined in paranthesis.

>>> Out ? b

This line just reads from the Out channel into b variable. This variable is not going to be used, but it has to be defined since the Test Purpose has to define what should be done with all the channels.

>>>” is the Enable Operator. It means that the flow synchronizes on EXIT of multiple processes. Here it signals the continuation after exiting the previous block.

Next block in paranthesis “()” enforces repeating the same sex for a number of times, for both sexes, then increments the repetition number and repeats:

(
    [[pos == length ]] =>> (
                             [[ isMale(s) ]] =>> repeatAndSwitchGender [In,Out] (1, length, Female)
                           ##
                             [[ isFemale(s) ]] =>> repeatAndSwitchGender [In,Out] (1, length+1, Male)
                           )
    ##
    [[pos < length ]] =>> repeatAndSwitchGender [In, Out] (pos+1,length, s)
)

If current position counter (pos) reached the requested length, then switch the genders. We start with Males, so after having requested number (length) of Males in a row, it’s time to request the same number of Females. After having the same number of Females, switch back to Males and increment the requested length.

If current position counter (pos) is still below the requested length, then just increment the position counter and request another person of the same sex with previous person.

There’s no upper limit defined for the repetition number (length), so as long as we run TorXakis the generated persons’ genders will be like this: MFMMFFMMMFFFMMMMFFFF

The Test Purpose

Let’s write a Test Purpose that uses repeatAndSwitchGender process to manipulate test data generated by TorXakis:

PURPDEF PurposeLuckyByGender ::=
    CHAN IN    In
    CHAN OUT   Out

    GOAL luckyByGender ::= repeatAndSwitchGender [In,Out] (1,1,Male)
ENDDEF

Now we can use this Test Purpose to test SUT for various “Lucky by gender” cases.

  1. Start the SUT: run the Java program in a command window.

$> java LuckyPeople

  1. Start TorXakis: run the TorXakis with the LuckyPeople model and PurposeLuckyByGender test purpose in another command window.

$> torxakis LuckyPeople.txs PurposeLuckyByGender.txs

  1. Set the Model, Test Purpose and SUT for testing: In TorXakis type the following commands:

tester Model PurposeLuckyByGender Sut

  1. Test the SUT with random data, ensuring coverage of “Lucky by gender” cases. Let’s say we test for repetitions of 1 to 10 i.e.:

  • Female after 1 Male

  • Male after 1 Female

  • Female after 2 Males

  • Male after 2 Females

  • Female after 9 Males

  • Male after 9 Females

  • Female after 10 Males

  • Male after 10 Females

This means we have (10*11)/2=55 cases for each gender, 2 steps (In, Out) per case means 110 steps and for both genders including last switch from 10F-to-M 221 steps in total. But TorXakis occasionally adds some Quiescence steps in between, so let’s run TorXakis for 300 steps instead. In TorXakis type the following command:

test 300

TXS >>  .....1: OUT: No Output (Quiescence)
TXS >>  .....2: IN: Act { { ( In, [ Person(Male,"Ac","Arv",13,5) ] ) } }
TXS >>  .....3: OUT: Act { { ( Out, [ True ] ) } }
TXS >>  .....4: OUT: No Output (Quiescence)
TXS >>  .....5: IN: Act { { ( In, [ Person(Female,"B","D",19,7) ] ) } }
TXS >>  .....6: OUT: Act { { ( Out, [ False ] ) } }
TXS >>  .....7: OUT: No Output (Quiescence)
TXS >>  .....8: IN: Act { { ( In, [ Person(Male,"D","H",29,7) ] ) } }
TXS >>  .....9: OUT: Act { { ( Out, [ False ] ) } }
TXS >>  ....10: OUT: No Output (Quiescence)
TXS >>  ....11: IN: Act { { ( In, [ Person(Male,"F","O",30,1) ] ) } }
TXS >>  ....12: OUT: Act { { ( Out, [ False ] ) } }
TXS >>  ....13: OUT: No Output (Quiescence)
TXS >>  ....14: IN: Act { { ( In, [ Person(Female,"A","D",2,3) ] ) } }
TXS >>  ....15: OUT: Act { { ( Out, [ False ] ) } }
TXS >>  ....16: OUT: No Output (Quiescence)
TXS >>  ....17: IN: Act { { ( In, [ Person(Female,"C","Pxd",3,12) ] ) } }
TXS >>  ....18: OUT: Act { { ( Out, [ False ] ) } }
TXS >>  ....19: OUT: No Output (Quiescence)
...
TXS >>  ...255: IN: Act { { ( In, [ Person(Male,"T","B",31,10) ] ) } }
TXS >>  ...256: OUT: Act { { ( Out, [ False ] ) } }
TXS >>  ...257: IN: Act { { ( In, [ Person(Female,"B","D",29,8) ] ) } }
TXS >>  ...258: OUT: Act { { ( Out, [ True ] ) } }
TXS >>  ...259: IN: Act { { ( In, [ Person(Female,"Yj","L",31,2) ] ) } }
TXS >>  ...260: OUT: Act { { ( Out, [ False ] ) } }
TXS >>  ...261: IN: Act { { ( In, [ Person(Female,"N","H",9,11) ] ) } }
TXS >>  ...262: OUT: Act { { ( Out, [ False ] ) } }
TXS >>  ...263: IN: Act { { ( In, [ Person(Female,"Pdp","A",5,7) ] ) } }
TXS >>  ...264: OUT: Act { { ( Out, [ False ] ) } }
TXS >>  ...265: IN: Act { { ( In, [ Person(Female,"Lh","H",30,11) ] ) } }
TXS >>  ...266: OUT: Act { { ( Out, [ False ] ) } }
TXS >>  ...267: IN: Act { { ( In, [ Person(Female,"Z","P",31,10) ] ) } }
TXS >>  ...268: OUT: Act { { ( Out, [ False ] ) } }
TXS >>  ...269: OUT: No Output (Quiescence)
TXS >>  ...270: IN: Act { { ( In, [ Person(Female,"V","C",18,9) ] ) } }
TXS >>  ...271: OUT: Act { { ( Out, [ False ] ) } }
TXS >>  ...272: IN: Act { { ( In, [ Person(Female,"Hbx","H",30,1) ] ) } }
TXS >>  ...273: OUT: Act { { ( Out, [ True ] ) } }
TXS >>  ...274: IN: Act { { ( In, [ Person(Female,"D","K",18,1) ] ) } }
TXS >>  ...275: OUT: Act { { ( Out, [ False ] ) } }
TXS >>  ...276: OUT: No Output (Quiescence)
TXS >>  ...277: IN: Act { { ( In, [ Person(Female,"Wp","Pkx",29,12) ] ) } }
TXS >>  ...278: OUT: Act { { ( Out, [ False ] ) } }
TXS >>  ...279: OUT: No Output (Quiescence)
TXS >>  ...280: IN: Act { { ( In, [ Person(Male,"G","Ahagpa",14,4) ] ) } }    <<== This is a Male after 10 Females
TXS >>  ...281: OUT: Act { { ( Out, [ True ] ) } }                            <<== He's lucky based on gender
TXS >>  ...282: OUT: No Output (Quiescence)
TXS >>  ...283: IN: Act { { ( In, [ Person(Male,"F","A",30,8) ] ) } }
TXS >>  ...284: OUT: Act { { ( Out, [ False ] ) } }
...
TXS >>  ...299: IN: Act { { ( In, [ Person(Male,"M","P",23,6) ] ) } }
TXS >>  ...300: OUT: Act { { ( Out, [ False ] ) } }
TXS >>  PASS

Point for attention: In our repeatAndSwitchGender process we didn’t have to tell TorXakis that after switching the gender the next person has to be lucky on unlucky; we just enforced a certain sex to be assigned to current person. TorXakis knows what each person’s luckiness output should be depending on the Model.