Automatic Teller Machine


I want to make an Automatic Teller Machine that shows different outputs, if the inputs are

  • is the PIN correct?

  • is the requested amount smaller or bigger than what is in the account?

then this is the truth table I get

PIN

balance

withdrawal

right PIN

enough

CASH

right PIN

NOT enough

DENIED

wrong PIN

yes

DENIED

wrong PIN

NOT enough

DENIED

preview

These are the tests I have at the end of the chapter

  1import src.atm
  2import unittest
  3
  4
  5class TestATM(unittest.TestCase):
  6
  7    def test_atm_withdrawal(self):
  8        my_expectation = 'CASH'
  9        self.assertEqual(
 10            src.atm.withdraw(
 11                card_has_expired=False,
 12                pin_is_correct=True,
 13                balance_is_enough=True,
 14                above_daily_limit=False,
 15            ),
 16            my_expectation
 17        )
 18
 19        my_expectation = 'DENIED'
 20
 21        self.assertEqual(
 22            src.atm.withdraw(
 23                card_has_expired=True,
 24                pin_is_correct=True,
 25                balance_is_enough=True,
 26                above_daily_limit=True,
 27            ),
 28            my_expectation
 29        )
 30
 31        self.assertEqual(
 32            src.atm.withdraw(
 33                card_has_expired=True,
 34                pin_is_correct=True,
 35                balance_is_enough=True,
 36                above_daily_limit=False,
 37            ),
 38            my_expectation
 39        )
 40
 41        self.assertEqual(
 42            src.atm.withdraw(
 43                card_has_expired=True,
 44                pin_is_correct=True,
 45                balance_is_enough=False,
 46                above_daily_limit=True,
 47            ),
 48            my_expectation
 49        )
 50
 51        self.assertEqual(
 52            src.atm.withdraw(
 53                card_has_expired=True,
 54                pin_is_correct=True,
 55                balance_is_enough=False,
 56                above_daily_limit=False,
 57            ),
 58            my_expectation
 59        )
 60
 61        self.assertEqual(
 62            src.atm.withdraw(
 63                card_has_expired=True,
 64                pin_is_correct=False,
 65                balance_is_enough=True,
 66                above_daily_limit=True,
 67            ),
 68            my_expectation
 69        )
 70
 71        self.assertEqual(
 72            src.atm.withdraw(
 73                card_has_expired=True,
 74                pin_is_correct=False,
 75                balance_is_enough=True,
 76                above_daily_limit=False,
 77            ),
 78            my_expectation
 79        )
 80
 81        self.assertEqual(
 82            src.atm.withdraw(
 83                card_has_expired=True,
 84                pin_is_correct=False,
 85                balance_is_enough=False,
 86                above_daily_limit=True,
 87            ),
 88            my_expectation
 89        )
 90
 91        self.assertEqual(
 92            src.atm.withdraw(
 93                card_has_expired=True,
 94                pin_is_correct=False,
 95                balance_is_enough=False,
 96                above_daily_limit=False
 97            ),
 98            my_expectation
 99        )
100
101        self.assertEqual(
102            src.atm.withdraw(
103                card_has_expired=False,
104                pin_is_correct=True,
105                balance_is_enough=True,
106                above_daily_limit=True,
107            ),
108            my_expectation
109        )
110
111        self.assertEqual(
112            src.atm.withdraw(
113                card_has_expired=False,
114                pin_is_correct=True,
115                balance_is_enough=False,
116                above_daily_limit=True,
117            ),
118            my_expectation
119        )
120
121        self.assertEqual(
122            src.atm.withdraw(
123                card_has_expired=False,
124                pin_is_correct=True,
125                balance_is_enough=False,
126                above_daily_limit=False,
127            ),
128            my_expectation
129        )
130
131        self.assertEqual(
132            src.atm.withdraw(
133                card_has_expired=False,
134                pin_is_correct=False,
135                balance_is_enough=True,
136                above_daily_limit=True,
137            ),
138            my_expectation
139        )
140
141        self.assertEqual(
142            src.atm.withdraw(
143                card_has_expired=False,
144                pin_is_correct=False,
145                balance_is_enough=True,
146                above_daily_limit=False,
147            ),
148            my_expectation
149        )
150
151        self.assertEqual(
152            src.atm.withdraw(
153                card_has_expired=False,
154                pin_is_correct=False,
155                balance_is_enough=False,
156                above_daily_limit=True,
157            ),
158            my_expectation
159        )
160
161        self.assertEqual(
162            src.atm.withdraw(
163                card_has_expired=False,
164                pin_is_correct=False,
165                balance_is_enough=False,
166                above_daily_limit=False,
167            ),
168            my_expectation
169        )
170
171
172# Exceptions seen
173# AssertionError
174# NameError
175# AttributeError
176# TypeError

requirements


start the project

  • I name this project atm

  • I open a terminal

  • I make a directory for the project

    mkdir atm
    

    the terminal goes back to the command line

  • I change directory to the project

    cd atm
    

    the terminal is my friend, and shows I am in the atm folder

    .../pumping_python/atm
    
  • I make a directory for the source code

    mkdir src
    

    the terminal goes back to the command line

  • I make a Python file to hold the source code in the src directory

    touch src/atm.py
    
    New-Item src/atm.py
    

    the terminal goes back to the command line

  • I make a directory for the tests

    mkdir tests
    

    the terminal goes back to the command line

  • I make the tests directory a Python package

    Danger

    use 2 underscores (__) before and after init for __init__.py not _init_.py

    touch tests/__init__.py
    
    New-Item tests/__init__.py
    

    the terminal goes back to the command line

  • I make a Python file for the tests in the tests directory

    touch tests/test_atm.py
    
    New-Item tests/test_atm.py
    

    the terminal goes back to the command line

  • I open test_atm.py in the editor of the Integrated Development Environment (IDE)

    Tip

    I can open a file from the terminal in the Integrated Development Environment (IDE) with the name of the program and the name of the file. That means if I type this in the terminal

    code tests/test_atm.py
    

    Visual Studio Code opens test_atm.py in the editor

  • I add the first failing test to test_atm.py

    1import unittest
    2
    3
    4class TestATM(unittest.TestCase):
    5
    6    def test_failure(self):
    7        self.assertFalse(True)
    
  • I make a requirements file for the Python packages I need, in the terminal

    echo "pytest" > requirements.txt
    

    the terminal goes back to the command line

  • I add pytest-watcher to the file

    echo "pytest-watcher" >> requirements.txt
    

    the terminal goes back to the command line

  • I set up the project with uv

    uv init
    

    the terminal shows

    Initialized project `atm`
    

    then goes back to the command line

  • I remove main.py from the project because I do not use it

    rm main.py
    

    the terminal goes back to the command line

  • I install the Python packages that I wrote in the requirements file

    uv add --requirement requirements.txt
    

    the terminal shows that it installed the Python packages

  • I use pytest-watcher to run the tests automatically

    uv run pytest-watcher . --now
    

    the terminal is my friend, and shows

    ================================ FAILURES ================================
    _________________________ TestATM.test_failure ___________________________
    
    self = <tests.test_atm.TestATM testMethod=test_failure>
    
        def test_failure(self):
    >       self.assertFalse(True)
    E       AssertionError: True is not false
    
    tests/test_atm.py:7: AssertionError
    ======================== short test summary info =========================
    FAILED tests/test_atm.py::TestATM::test_failure - AssertionError: True is not false
    =========================== 1 failed in X.YZs ============================
    
  • I add AssertionError to the list of Exceptions seen in test_atm.py

     4class TestATM(unittest.TestCase):
     5
     6    def test_failure(self):
     7        self.assertFalse(True)
     8
     9
    10# Exceptions seen
    11# AssertionError
    
  • then I change True to False in the assertion

    7        self.assertFalse(False)
    

    the test passes


test_atm_withdrawal


RED: make it fail


I change test_failure to test_atm_withdrawal, then add an assertion for when the right PIN is entered and there is enough money in the account

PIN

balance

withdrawal

right PIN

enough

CASH

 4class TestATM(unittest.TestCase):
 5
 6    def test_atm_withdrawal(self):
 7        my_expectation = 'CASH'
 8        reality = src.atm.withdraw(
 9            pin_is_correct=True,
10            balance_is_enough=True,
11        )
12        self.assertEqual(reality, my_expectation)
13
14
15# Exceptions seen
16# AssertionError

the terminal is my friend, and shows NameError

NameError: name 'src' is not defined

GREEN: make it pass


  • I add NameError to the list of Exceptions seen

    15# Exceptions seen
    16# AssertionError
    17# NameError
    
  • I add an import statement at the top of the file

    1import src.atm
    2import unittest
    3
    4
    5class TestATM(unittest.TestCase):
    

    the terminal is my friend, and shows AttributeError

    AttributeError: module 'src.atm' has no attribute 'withdraw'
    
  • I add AttributeError to the list of Exceptions seen

    16# Exceptions seen
    17# AssertionError
    18# NameError
    19# AttributeError
    
  • I open atm.py from the src folder in the editor

  • I add a function to atm.py

    1def withdraw():
    2    return None
    

    the terminal is my friend, and shows TypeError

    TypeError: withdraw() got an unexpected keyword argument 'pin_is_correct'
    
  • I add TypeError to the list of Exceptions seen in test_atm.py

    16# Exceptions seen
    17# AssertionError
    18# NameError
    19# AttributeError
    20# TypeError
    
  • I add the keyword argument to the function in atm.py

    1def withdraw(pin_is_correct):
    2    return None
    

    the terminal is my friend, and shows TypeError

    TypeError: withdraw() got an unexpected keyword argument 'balance_is_enough'
    
  • I add balance_is_enough to the function signature

    1def withdraw(pin_is_correct, balance_is_enough):
    2    return None
    

    the terminal is my friend, and shows AssertionError

    AssertionError: None != 'CASH'
    
  • I change the return statement to give the test what it expects

    1def withdraw(pin_is_correct, balance_is_enough):
    2    return 'CASH'
    

    the test passes. The withdraw function always returns CASH, it does not care about the inputs. Is this Tautology?


REFACTOR: make it better


  • I add an assertion for when the right PIN is entered AND there is NOT enough money in the account

    PIN

    balance

    withdrawal

    right PIN

    enough

    CASH

    right PIN

    NOT enough

    DENIED

     7    def test_atm_withdrawal(self):
     8        my_expectation = 'CASH'
     9        reality = src.atm.withdraw(
    10            pin_is_correct=True,
    11            balance_is_enough=True,
    12        )
    13        self.assertEqual(reality, my_expectation)
    14
    15        my_expectation = 'DENIED'
    16        reality = src.atm.withdraw(
    17            pin_is_correct=True,
    18            balance_is_enough=False,
    19        )
    20        self.assertEqual(reality, my_expectation)
    21
    22
    23# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: 'CASH' != 'DENIED'
    
  • I add an if statement to atm.py

    1def withdraw(pin_is_correct, balance_is_enough):
    2    if pin_is_correct and not balance_is_enough:
    3        return 'DENIED'
    4    return 'CASH'
    

    the test passes

  • I add an assertion for when the wrong PIN is entered and there is enough money in the account, to test_atm_withdrawal in test_atm.py

    PIN

    balance

    withdrawal

    right PIN

    enough

    CASH

    right PIN

    NOT enough

    DENIED

    wrong PIN

    yes

    DENIED

    the terminal is my friend, and shows AssertionError

    AssertionError: 'CASH' != 'DENIED'
    
  • I add an if statement for this case to atm.py

    1def withdraw(pin_is_correct, balance_is_enough):
    2    if not pin_is_correct and balance_is_enough:
    3        return 'DENIED'
    4    if pin_is_correct and not balance_is_enough:
    5        return 'DENIED'
    6    return 'CASH'
    

    the test passes

  • I add an assertion for the last case - when the wrong PIN is entered and there is NOT enough money left in the account, in test_atm.py

    PIN

    balance

    withdrawal

    right PIN

    enough

    CASH

    right PIN

    NOT enough

    DENIED

    wrong PIN

    yes

    DENIED

    wrong PIN

    NOT enough

    DENIED

     7    def test_atm_withdrawal(self):
     8        my_expectation = 'CASH'
     9        reality = src.atm.withdraw(
    10            pin_is_correct=True,
    11            balance_is_enough=True,
    12        )
    13        self.assertEqual(reality, my_expectation)
    14
    15        my_expectation = 'DENIED'
    16        reality = src.atm.withdraw(
    17            pin_is_correct=True,
    18            balance_is_enough=False,
    19        )
    20        self.assertEqual(reality, my_expectation)
    21
    22        my_expectation = 'DENIED'
    23        reality = src.atm.withdraw(
    24            pin_is_correct=False,
    25            balance_is_enough=True,
    26        )
    27        self.assertEqual(reality, my_expectation)
    28
    29        my_expectation = 'DENIED'
    30        reality = src.atm.withdraw(
    31            pin_is_correct=False,
    32            balance_is_enough=False,
    33        )
    34        self.assertEqual(reality, my_expectation)
    35
    36
    37# Exceptions seen
    

    the terminal is my friend, and shows AssertionError

    AssertionError: 'CASH' != 'DENIED'
    
  • I add an if statement to atm.py for the last case

    1def withdraw(pin_is_correct, balance_is_enough):
    2    if not pin_is_correct and not balance_is_enough:
    3        return 'DENIED'
    4    if not pin_is_correct and balance_is_enough:
    5        return 'DENIED'
    6    if pin_is_correct and not balance_is_enough:
    7        return 'DENIED'
    8    return 'CASH'
    

    the test passes

  • 3 of the cases return 'DENIED' and only one case returns 'CASH'. I add an if statement with an else clause for the one case

     1def withdraw(pin_is_correct, balance_is_enough):
     2    if pin_is_correct and balance_is_enough:
     3        return 'CASH'
     4    else:
     5        return 'DENIED'
     6    if not pin_is_correct and not balance_is_enough:
     7        return 'DENIED'
     8    if not pin_is_correct and balance_is_enough:
     9        return 'DENIED'
    10    if pin_is_correct and not balance_is_enough:
    11        return 'DENIED'
    12    return 'CASH'
    

    the test is still green

  • I remove the other if statements

    1def withdraw(pin_is_correct, balance_is_enough):
    2    if pin_is_correct and balance_is_enough:
    3        return 'CASH'
    4    else:
    5        return 'DENIED'
    

    still green

  • I do not need to make the my_expectation variable 3 times in test_atm.py since it is the same value every time. I remove the repetition from test_atm.py

     7    def test_atm_withdrawal(self):
     8        my_expectation = 'CASH'
     9        reality = src.atm.withdraw(
    10            pin_is_correct=True,
    11            balance_is_enough=True,
    12        )
    13        self.assertEqual(reality, my_expectation)
    14
    15        my_expectation = 'DENIED'
    16
    17        reality = src.atm.withdraw(
    18            pin_is_correct=True,
    19            balance_is_enough=False,
    20        )
    21        self.assertEqual(reality, my_expectation)
    22
    23        reality = src.atm.withdraw(
    24            pin_is_correct=False,
    25            balance_is_enough=True,
    26        )
    27        self.assertEqual(reality, my_expectation)
    28
    29        reality = src.atm.withdraw(
    30            pin_is_correct=False,
    31            balance_is_enough=False,
    32        )
    33        self.assertEqual(reality, my_expectation)
    34
    35
    36# Exceptions seen
    

    green


test_atm_withdrawal_w_daily_limit

So far, the truth table for the Automatic Teller Machine is

PIN

balance

withdrawal

right PIN

enough

CASH

right PIN

NOT enough

DENIED

wrong PIN

yes

DENIED

wrong PIN

NOT enough

DENIED

I want to add a condition for a daily limit on how much can be withdrawn from the account.The inputs for the ATM will then be

  • is the PIN correct?

  • is the requested amount smaller or bigger than what is in the account?

  • will this put the account above or below the daily limit for withdrawals?

the truth table for the ATM will now be

PIN

balance

daily limit

withdrawal

right PIN

enough

above limit

DENIED

right PIN

enough

below limit

CASH

right PIN

NOT enough

above limit

DENIED

right PIN

NOT enough

below limit

DENIED

wrong PIN

enough

above limit

DENIED

wrong PIN

enough

below limit

DENIED

wrong PIN

NOT enough

above limit

DENIED

wrong PIN

NOT enough

below limit

DENIED


RED: make it fail


I add an assertion for the first case where the right PIN is entered, the account balance is enough and the account is above limit for daily withdrawals, to test_atm_withdrawal in test_atm.py

PIN

balance

daily limit

withdrawal

right PIN

enough

above limit

DENIED

 7      def test_atm_withdrawal(self):
 8          my_expectation = 'DENIED'
 9          reality = src.atm.withdraw(
10              pin_is_correct=True,
11              balance_is_enough=True,
12              above_daily_limit=True,
13          )
14          self.assertEqual(reality, my_expectation)
15
16          my_expectation = 'CASH'
17          reality = src.atm.withdraw(
18              pin_is_correct=True,
19              balance_is_enough=True,
20          )
21          self.assertEqual(reality, my_expectation)

the terminal is my friend, and shows TypeError

TypeError: withdraw() got an unexpected keyword argument 'above_daily_limit'

GREEN: make it pass


  • I add above_daily_limit to the function in atm.py

    1def withdraw(
    2        pin_is_correct, balance_is_enough,
    3        above_daily_limit,
    4    ):
    5    if pin_is_correct and balance_is_enough:
    

    the terminal is my friend, and shows AssertionError

    AssertionError: 'CASH' != 'DENIED'
    
  • I add an if statement

     5    if pin_is_correct and balance_is_enough:
     6        if above_daily_limit:
     7            return 'DENIED'
     8        return 'CASH'
     9    else:
    10        return 'DENIED'
    

    the terminal is my friend, and shows TypeError

    TypeError: withdraw() missing 1 required positional argument: 'above_daily_limit'
    
  • I add a default value for above_daily_limit to make it a choice

     1def withdraw(
     2        pin_is_correct, balance_is_enough,
     3        above_daily_limit=False,
     4    ):
     5    if pin_is_correct and balance_is_enough:
     6        if above_daily_limit:
     7            return 'DENIED'
     8        return 'CASH'
     9    else:
    10        return 'DENIED'
    

    the test passes.


REFACTOR: make it better


  • I do not need to add anything to the second assertion in test_atm_withdrawal because the default value for the above_daily_limit parameter of the withdraw function is False

    PIN

    balance

    daily limit

    withdrawal

    right PIN

    enough

    above limit

    DENIED

    right PIN

    enough

    below limit

    CASH

    this means

    reality = src.atm.withdraw(
        pin_is_correct=True,
        balance_is_enough=True,
    )
    

    is the same as

    reality = src.atm.withdraw(
        pin_is_correct=True,
        balance_is_enough=True,
        above_daily_limit=False,
    )
    
  • I add an assertion for the case where the right PIN is entered, the account balance is NOT enough and the account is above limit for daily withdrawals, in test_atm.py

    PIN

    balance

    daily limit

    withdrawal

    right PIN

    enough

    above limit

    DENIED

    right PIN

    enough

    below limit

    CASH

    right PIN

    NOT enough

    above limit

    DENIED

     7    def test_atm_withdrawal(self):
     8        my_expectation = 'DENIED'
     9        reality = src.atm.withdraw(
    10            pin_is_correct=True,
    11            balance_is_enough=True,
    12            above_daily_limit=True,
    13        )
    14        self.assertEqual(reality, my_expectation)
    15
    16        my_expectation = 'CASH'
    17        reality = src.atm.withdraw(
    18            pin_is_correct=True,
    19            balance_is_enough=True,
    20        )
    21        self.assertEqual(reality, my_expectation)
    22
    23        my_expectation = 'DENIED'
    24
    25        reality = src.atm.withdraw(
    26            pin_is_correct=True,
    27            balance_is_enough=False,
    28            above_daily_limit=True,
    29        )
    30        self.assertEqual(reality, my_expectation)
    31
    32        reality = src.atm.withdraw(
    33            pin_is_correct=True,
    34            balance_is_enough=False,
    35        )
    36        self.assertEqual(reality, my_expectation)
    

    the test is still green

  • I do not need to add anything to the fourth assertion for when the right PIN is entered, the balance is NOT enough and the account is below limit for daily withdrawals, because the default value for the above_daily_limit parameter of the withdraw function is False

    PIN

    balance

    daily limit

    withdrawal

    right PIN

    enough

    above limit

    DENIED

    right PIN

    enough

    below limit

    CASH

    right PIN

    NOT enough

    above limit

    DENIED

    right PIN

    NOT enough

    below limit

    DENIED

    this means

    reality = src.atm.withdraw(
        pin_is_correct=True,
        balance_is_enough=False,
    )
    

    is the same as

    reality = src.atm.withdraw(
        pin_is_correct=True,
        balance_is_enough=False,
        above_daily_limit=False,
    )
    
  • I add above_daily_limit to the fifth assertion for the case where the wrong PIN is entered, the account balance is enough and the account is above limit for daily withdrawals

    PIN

    balance

    daily limit

    withdrawal

    wrong PIN

    enough

    above limit

    DENIED

     7    def test_atm_withdrawal(self):
     8        my_expectation = 'DENIED'
     9        reality = src.atm.withdraw(
    10            pin_is_correct=True,
    11            balance_is_enough=True,
    12            above_daily_limit=True,
    13        )
    14        self.assertEqual(reality, my_expectation)
    15
    16        my_expectation = 'CASH'
    17        reality = src.atm.withdraw(
    18            pin_is_correct=True,
    19            balance_is_enough=True,
    20        )
    21        self.assertEqual(reality, my_expectation)
    22
    23        my_expectation = 'DENIED'
    24
    25        reality = src.atm.withdraw(
    26            pin_is_correct=True,
    27            balance_is_enough=False,
    28            above_daily_limit=True,
    29        )
    30        self.assertEqual(reality, my_expectation)
    31
    32        reality = src.atm.withdraw(
    33            pin_is_correct=True,
    34            balance_is_enough=False,
    35        )
    36        self.assertEqual(reality, my_expectation)
    37
    38        reality = src.atm.withdraw(
    39            pin_is_correct=False,
    40            balance_is_enough=True,
    41            above_daily_limit=True,
    42        )
    43        self.assertEqual(reality, my_expectation)
    44
    45        reality = src.atm.withdraw(
    46            pin_is_correct=False,
    47            balance_is_enough=False,
    48        )
    49        self.assertEqual(reality, my_expectation)
    50
    51
    52# Exceptions seen
    

    still green

  • I do not need to add anything to the sixth assertion for when the wrong PIN is entered, the balance is NOT enough and the account is below limit for daily withdrawals, because the default value for the above_daily_limit parameter of the withdraw function is False

    PIN

    balance

    daily limit

    withdrawal

    wrong PIN

    enough

    above limit

    DENIED

    wrong PIN

    enough

    below limit

    DENIED

    this means

    reality = src.atm.withdraw(
        pin_is_correct=False,
        balance_is_enough=False,
    )
    

    is the same as

    reality = src.atm.withdraw(
        pin_is_correct=False,
        balance_is_enough=False,
        above_daily_limit=False,
    )
    
  • I add an assertion for the when the wrong PIN is entered, the balance is NOT enough and the account is above limit for daily withdrawals

    PIN

    balance

    daily limit

    withdrawal

    wrong PIN

    enough

    above limit

    DENIED

    wrong PIN

    enough

    below limit

    DENIED

    wrong PIN

    NOT enough

    above limit

    DENIED

    38        reality = src.atm.withdraw(
    39            pin_is_correct=False,
    40            balance_is_enough=True,
    41            above_daily_limit=True,
    42        )
    43        self.assertEqual(reality, my_expectation)
    44
    45        reality = src.atm.withdraw(
    46            pin_is_correct=False,
    47            balance_is_enough=False,
    48        )
    49        self.assertEqual(reality, my_expectation)
    50
    51        reality = src.atm.withdraw(
    52            pin_is_correct=False,
    53            balance_is_enough=False,
    54            above_daily_limit=True
    55        )
    56        self.assertEqual(reality, my_expectation)
    57
    58
    59# Exceptions seen
    

    green

  • I add an assertion for when the wrong PIN is entered, the balance is NOT enough and the account is below limit for daily withdrawals

    PIN

    balance

    daily limit

    withdrawal

    wrong PIN

    enough

    above limit

    DENIED

    wrong PIN

    enough

    below limit

    DENIED

    wrong PIN

    NOT enough

    above limit

    DENIED

    wrong PIN

    NOT enough

    below limit

    DENIED

    51        reality = src.atm.withdraw(
    52            pin_is_correct=False,
    53            balance_is_enough=False,
    54            above_daily_limit=True
    55        )
    56        self.assertEqual(reality, my_expectation)
    57
    58        reality = src.atm.withdraw(
    59            pin_is_correct=False,
    60            balance_is_enough=False,
    61        )
    62        self.assertEqual(reality, my_expectation)
    63
    64
    65# Exceptions seen
    

    still green

  • I move the assertion for the one case where the ATM gives cash, to the top and remove the second my_expectation variable

     7    def test_atm_withdrawal(self):
     8        my_expectation = 'CASH'
     9        reality = src.atm.withdraw(
    10            pin_is_correct=True,
    11            balance_is_enough=True,
    12        )
    13        self.assertEqual(reality, my_expectation)
    14
    15        my_expectation = 'DENIED'
    16
    17        reality = src.atm.withdraw(
    18            pin_is_correct=True,
    19            balance_is_enough=True,
    20            above_daily_limit=True,
    21        )
    22        self.assertEqual(reality, my_expectation)
    23
    24        reality = src.atm.withdraw(
    25            pin_is_correct=True,
    26            balance_is_enough=False,
    27            above_daily_limit=True,
    28        )
    29        self.assertEqual(reality, my_expectation)
    30
    31        reality = src.atm.withdraw(
    32            pin_is_correct=True,
    33            balance_is_enough=False,
    34        )
    35        self.assertEqual(reality, my_expectation)
    36
    37        reality = src.atm.withdraw(
    38            pin_is_correct=False,
    39            balance_is_enough=True,
    40            above_daily_limit=True,
    41        )
    42        self.assertEqual(reality, my_expectation)
    43
    44        reality = src.atm.withdraw(
    45            pin_is_correct=False,
    46            balance_is_enough=False,
    47        )
    48        self.assertEqual(reality, my_expectation)
    49
    50        reality = src.atm.withdraw(
    51            pin_is_correct=False,
    52            balance_is_enough=False,
    53            above_daily_limit=True
    54        )
    55        self.assertEqual(reality, my_expectation)
    56
    57        reality = src.atm.withdraw(
    58            pin_is_correct=False,
    59            balance_is_enough=False,
    60        )
    61        self.assertEqual(reality, my_expectation)
    62
    63
    64# Exceptions seen
    
  • There is only one case where the withdraw function returns 'CASH'. I add if statements for the other cases to atm.py

     1def withdraw(
     2        pin_is_correct, balance_is_enough,
     3        above_daily_limit=False,
     4    ):
     5    denial = 'DENIED'
     6
     7    if not pin_is_correct:
     8        return denial
     9    if not balance_is_enough:
    10        return denial
    11    if above_daily_limit:
    12        return denial
    13
    14    if pin_is_correct and balance_is_enough:
    15        if above_daily_limit:
    16            return 'DENIED'
    17        return 'CASH'
    18    else:
    19        return 'DENIED'
    

    the test is still green.

    The ATM

    • denies a withdrawal if the wrong PIN is entered because you cannot enter the system

    • denies a withdrawal if the account balance is NOT enough. This only happens if the right PIN is entered.

    • denies a withdrawal if the account is above limit for the daily withdrawal limit. This only happens if the account balance is enough.

  • I add a return statement for the one case where the withdrawal is allowed

     1def withdraw(
     2        pin_is_correct, balance_is_enough,
     3        above_daily_limit=False,
     4    ):
     5    denial = 'DENIED'
     6
     7    if not pin_is_correct:
     8        return denial
     9    if not balance_is_enough:
    10        return denial
    11    if above_daily_limit:
    12        return denial
    13    return 'CASH'
    14
    15    if pin_is_correct and balance_is_enough:
    16        if above_daily_limit:
    17            return 'DENIED'
    18        return 'CASH'
    19    else:
    20        return 'DENIED'
    

    still green.

    The ATM

    • denies a withdrawal if the wrong PIN is entered because you cannot enter the system

    • denies a withdrawal if the account balance is NOT enough. This only happens if the right PIN is entered.

    • denies a withdrawal if the account is above limit for the daily withdrawal limit. This only happens if the account balance is enough.

    • approves a withdrawal only if the right PIN is entered and the balance is enough and the account is below limit for daily withdrawals

  • I remove the other statements

     1def withdraw(
     2        pin_is_correct, balance_is_enough,
     3        above_daily_limit=False,
     4    ):
     5    denial = 'DENIED'
     6
     7    if not pin_is_correct:
     8        return denial
     9    if not balance_is_enough:
    10        return denial
    11    if above_daily_limit:
    12        return denial
    13    return 'CASH'
    

test_atm_withdrawal_w_expired_bank_card

The truth table for the Automatic Teller Machine is now

PIN

balance

daily limit

withdrawal

right PIN

enough

above limit

DENIED

right PIN

enough

below limit

CASH

right PIN

NOT enough

above limit

DENIED

right PIN

NOT enough

below limit

DENIED

wrong PIN

enough

above limit

DENIED

wrong PIN

enough

below limit

DENIED

wrong PIN

NOT enough

above limit

DENIED

wrong PIN

NOT enough

below limit

DENIED

I want to add a condition for when the bank card is expired.The inputs for the ATM will then be

  • has the card expired?

  • is the PIN correct?

  • is the requested amount smaller or bigger than what is in the account?

  • will this put the account above or below the daily limit for withdrawals?

the truth table for the ATM will now be

card expired

PIN

balance

daily limit

withdrawal

expired

right PIN

enough

above limit

DENIED

expired

right PIN

enough

below limit

DENIED

expired

right PIN

NOT enough

above limit

DENIED

expired

right PIN

NOT enough

below limit

DENIED

expired

wrong PIN

enough

above limit

DENIED

expired

wrong PIN

enough

below limit

DENIED

expired

wrong PIN

NOT enough

above limit

DENIED

expired

wrong PIN

NOT enough

below limit

DENIED

NOT expired

right PIN

enough

above limit

DENIED

NOT expired

right PIN

enough

below limit

CASH

NOT expired

right PIN

NOT enough

above limit

DENIED

NOT expired

right PIN

NOT enough

below limit

DENIED

NOT expired

wrong PIN

enough

above limit

DENIED

NOT expired

wrong PIN

enough

below limit

DENIED

NOT expired

wrong PIN

NOT enough

above limit

DENIED

NOT expired

wrong PIN

NOT enough

below limit

DENIED


RED: make it fail


I add a value for the card_expired parameter to the call to the withdraw function for the case where the card has expired, the right PIN is entered, the account balance is enough and the account is above limit for daily withdrawals, in test_atm_withdrawal in test_atm.py

card expired

PIN

balance

daily limit

withdrawal

expired

right PIN

enough

above limit

DENIED

 7    def test_atm_withdrawal(self):
 8        my_expectation = 'CASH'
 9        reality = src.atm.withdraw(
10            pin_is_correct=True,
11            balance_is_enough=True,
12        )
13        self.assertEqual(reality, my_expectation)
14
15        my_expectation = 'DENIED'
16
17        reality = src.atm.withdraw(
18            card_has_expired=True,
19            pin_is_correct=True,
20            balance_is_enough=True,
21            above_daily_limit=True,
22        )
23        self.assertEqual(reality, my_expectation)

the terminal is my friend, and shows TypeError

TypeError: withdraw() got an unexpected keyword argument 'card_has_expired'

GREEN: make it pass



REFACTOR: make it better


  • I add an assertion for when the card has expired, the right PIN is entered, the account balance is enough and the account is below limit for daily withdrawals, to test_atm_withdrawal in test_atm.py

    card expired

    PIN

    balance

    daily limit

    withdrawal

    expired

    right PIN

    enough

    above limit

    DENIED

    expired

    right PIN

    enough

    below limit

    DENIED

     7    def test_atm_withdrawal(self):
     8        my_expectation = 'CASH'
     9        reality = src.atm.withdraw(
    10            pin_is_correct=True,
    11            balance_is_enough=True,
    12        )
    13        self.assertEqual(reality, my_expectation)
    14
    15        my_expectation = 'DENIED'
    16
    17        reality = src.atm.withdraw(
    18            card_has_expired=True,
    19            pin_is_correct=True,
    20            balance_is_enough=True,
    21            above_daily_limit=True,
    22        )
    23        self.assertEqual(reality, my_expectation)
    24
    25        reality = src.atm.withdraw(
    26            card_has_expired=True,
    27            pin_is_correct=True,
    28            balance_is_enough=True,
    29            above_daily_limit=False,
    30        )
    31        self.assertEqual(reality, my_expectation)
    

    the terminal is my friend, and shows AssertionError

    AssertionError: 'CASH' != 'DENIED'
    
  • I add an if statement to the withdraw function in atm.py

     1def withdraw(
     2        pin_is_correct, balance_is_enough,
     3        above_daily_limit=False, card_has_expired=False,
     4    ):
     5    denial = 'DENIED'
     6
     7    if card_has_expired:
     8        return denial
     9    if not pin_is_correct:
    10        return denial
    11    if not balance_is_enough:
    12        return denial
    13    if above_daily_limit:
    14        return denial
    15    return 'CASH'
    

    the test passes. the ATM

    • denies a withdrawal if the card has expired, it will NOT check the PIN.

    • denies a withdrawal if the wrong PIN is entered because you cannot enter the system.

    • denies a withdrawal if the account balance is NOT enough. This only happens if the right PIN is entered.

    • denies a withdrawal if the account is above limit for the daily withdrawal limit. This only happens if the account balance is enough.

    • approves a withdrawal only if the card has NOT expired, the right PIN is entered, the balance is enough and the account is below limit for daily withdrawals

  • I add card_has_expired to the fourth assertion, which is for when the card has expired, the right PIN is entered, the balance is NOT enough and the account is above limit for daily withdrawals

    card expired

    PIN

    balance

    daily limit

    withdrawal

    expired

    right PIN

    enough

    above limit

    DENIED

    expired

    right PIN

    enough

    below limit

    DENIED

    expired

    right PIN

    NOT enough

    above limit

    DENIED

     7    def test_atm_withdrawal(self):
     8        my_expectation = 'CASH'
     9        reality = src.atm.withdraw(
    10            pin_is_correct=True,
    11            balance_is_enough=True,
    12        )
    13        self.assertEqual(reality, my_expectation)
    14
    15        my_expectation = 'DENIED'
    16
    17        reality = src.atm.withdraw(
    18            card_has_expired=True,
    19            pin_is_correct=True,
    20            balance_is_enough=True,
    21            above_daily_limit=True,
    22        )
    23        self.assertEqual(reality, my_expectation)
    24
    25        reality = src.atm.withdraw(
    26            card_has_expired=True,
    27            pin_is_correct=True,
    28            balance_is_enough=True,
    29            above_daily_limit=False,
    30        )
    31        self.assertEqual(reality, my_expectation)
    32
    33        reality = src.atm.withdraw(
    34            card_has_expired=True,
    35            pin_is_correct=True,
    36            balance_is_enough=False,
    37            above_daily_limit=True,
    38        )
    39        self.assertEqual(reality, my_expectation)
    

    the test is still green

  • I add card_has_expired to the fifth assertion, I also add above_daily_limit to be clearer. This is for the case where the card has expired, the right PIN is entered, the balance is NOT enough and the account is below limit for daily withdrawals

    card expired

    PIN

    balance

    daily limit

    withdrawal

    expired

    right PIN

    enough

    above limit

    DENIED

    expired

    right PIN

    enough

    below limit

    DENIED

    expired

    right PIN

    NOT enough

    above limit

    DENIED

    expired

    right PIN

    NOT enough

    below limit

    DENIED

    33        reality = src.atm.withdraw(
    34            card_has_expired=True,
    35            pin_is_correct=True,
    36            balance_is_enough=False,
    37            above_daily_limit=True,
    38        )
    39        self.assertEqual(reality, my_expectation)
    40
    41        reality = src.atm.withdraw(
    42            card_has_expired=True,
    43            pin_is_correct=True,
    44            balance_is_enough=False,
    45            above_daily_limit=False,
    46        )
    47        self.assertEqual(reality, my_expectation)
    48
    49        reality = src.atm.withdraw(
    50            pin_is_correct=False,
    51            balance_is_enough=True,
    52            above_daily_limit=True,
    53        )
    54        self.assertEqual(reality, my_expectation)
    

    still green


  • I add card_has_expired to the next assertion, for the case where the card has expired, the wrong PIN is entered, the balance is enough and the account is above limit for daily withdrawals

    card expired

    PIN

    balance

    daily limit

    withdrawal

    expired

    wrong PIN

    enough

    above limit

    DENIED

    41        reality = src.atm.withdraw(
    42            card_has_expired=True,
    43            pin_is_correct=True,
    44            balance_is_enough=False,
    45            above_daily_limit=False,
    46        )
    47        self.assertEqual(reality, my_expectation)
    48
    49        reality = src.atm.withdraw(
    50            card_has_expired=True,
    51            pin_is_correct=False,
    52            balance_is_enough=True,
    53            above_daily_limit=True,
    54        )
    55        self.assertEqual(reality, my_expectation)
    56
    57        reality = src.atm.withdraw(
    58            pin_is_correct=False,
    59            balance_is_enough=False,
    60        )
    61        self.assertEqual(reality, my_expectation)
    

    green

  • I add an assertion for the case where the card has expired, the wrong PIN is entered, the balance is enough and the account is below limit for daily withdrawals

    card expired

    PIN

    balance

    daily limit

    withdrawal

    expired

    wrong PIN

    enough

    above limit

    DENIED

    expired

    wrong PIN

    enough

    below limit

    DENIED

    41        reality = src.atm.withdraw(
    42            card_has_expired=True,
    43            pin_is_correct=False,
    44            balance_is_enough=True,
    45            above_daily_limit=True,
    46        )
    47        self.assertEqual(reality, my_expectation)
    48
    49        reality = src.atm.withdraw(
    50            card_has_expired=True,
    51            pin_is_correct=False,
    52            balance_is_enough=True,
    53            above_daily_limit=False,
    54        )
    55        self.assertEqual(reality, my_expectation)
    56
    57        reality = src.atm.withdraw(
    58            pin_is_correct=False,
    59            balance_is_enough=False,
    60        )
    61        self.assertEqual(reality, my_expectation)
    

    still green

  • I add card_has_expired and above_daily_limit to the next assertion, which is for when the card has expired, the wrong PIN is entered, the balance is NOT enough and the account is above limit for daily withdrawals

    card expired

    PIN

    balance

    daily limit

    withdrawal

    expired

    wrong PIN

    enough

    above limit

    DENIED

    expired

    wrong PIN

    enough

    below limit

    DENIED

    expired

    wrong PIN

    NOT enough

    above limit

    DENIED

    57        reality = src.atm.withdraw(
    58            card_has_expired=True,
    59            pin_is_correct=False,
    60            balance_is_enough=True,
    61            above_daily_limit=False,
    62        )
    63        self.assertEqual(reality, my_expectation)
    64
    65        reality = src.atm.withdraw(
    66            card_has_expired=True,
    67            pin_is_correct=False,
    68            balance_is_enough=False,
    69            above_daily_limit=True
    70        )
    71        self.assertEqual(reality, my_expectation)
    72
    73        reality = src.atm.withdraw(
    74            pin_is_correct=False,
    75            balance_is_enough=False,
    76            above_daily_limit=True
    77        )
    78        self.assertEqual(reality, my_expectation)
    

    the test is still green

  • I change the next assertion to be for when the card has expired, the wrong PIN is entered, the balance is NOT enough and the account is below limit for daily withdrawals

    card expired

    PIN

    balance

    daily limit

    withdrawal

    expired

    wrong PIN

    enough

    above limit

    DENIED

    expired

    wrong PIN

    enough

    below limit

    DENIED

    expired

    wrong PIN

    NOT enough

    above limit

    DENIED

    expired

    wrong PIN

    NOT enough

    below limit

    DENIED

    49        reality = src.atm.withdraw(
    50            card_has_expired=True,
    51            pin_is_correct=False,
    52            balance_is_enough=True,
    53            above_daily_limit=True,
    54        )
    55        self.assertEqual(reality, my_expectation)
    56
    57        reality = src.atm.withdraw(
    58            card_has_expired=True,
    59            pin_is_correct=False,
    60            balance_is_enough=True,
    61            above_daily_limit=False,
    62        )
    63        self.assertEqual(reality, my_expectation)
    64
    65        reality = src.atm.withdraw(
    66            card_has_expired=True,
    67            pin_is_correct=False,
    68            balance_is_enough=False,
    69            above_daily_limit=True,
    70        )
    71        self.assertEqual(reality, my_expectation)
    72
    73        reality = src.atm.withdraw(
    74            card_has_expired=True,
    75            pin_is_correct=False,
    76            balance_is_enough=False,
    77            above_daily_limit=False
    78        )
    79        self.assertEqual(reality, my_expectation)
    80
    81        reality = src.atm.withdraw(
    82            pin_is_correct=False,
    83            balance_is_enough=False,
    84        )
    85        self.assertEqual(reality, my_expectation)
    

    still green


  • I change the last assertion to be for when the card has NOT expired, the right PIN is entered, the balance is enough and the account is above limit for daily withdrawals

    card expired

    PIN

    balance

    daily limit

    withdrawal

    NOT expired

    right PIN

    enough

    above limit

    DENIED

    73        reality = src.atm.withdraw(
    74            card_has_expired=True,
    75            pin_is_correct=False,
    76            balance_is_enough=False,
    77            above_daily_limit=False
    78        )
    79        self.assertEqual(reality, my_expectation)
    80
    81        reality = src.atm.withdraw(
    82            card_has_expired=False,
    83            pin_is_correct=True,
    84            balance_is_enough=True,
    85            above_daily_limit=True,
    86        )
    87        self.assertEqual(reality, my_expectation)
    88
    89
    90# Exceptions
    

    green

  • I go back to the first assertion to add the card_has_expired and above_daily_limit parameters. This is the one case where the ATM gives cash - when the card has NOT expired, the right PIN is entered, the balance is enough and the account is below limit for daily withdrawals

    card expired

    PIN

    balance

    daily limit

    withdrawal

    NOT expired

    right PIN

    enough

    above limit

    DENIED

    NOT expired

    right PIN

    enough

    below limit

    CASH

     7    def test_atm_withdrawal(self):
     8        my_expectation = 'CASH'
     9        reality = src.atm.withdraw(
    10            card_has_expired=False,
    11            pin_is_correct=True,
    12            balance_is_enough=True,
    13            above_daily_limit=False,
    14        )
    15        self.assertEqual(reality, my_expectation)
    

    still green

  • I add an assertion for the case where the card has NOT expired, the right PIN is entered, the balance is NOT enough and the account is above limit for daily withdrawals

    card expired

    PIN

    balance

    daily limit

    withdrawal

    NOT expired

    right PIN

    enough

    above limit

    DENIED

    NOT expired

    right PIN

    enough

    below limit

    CASH

    NOT expired

    right PIN

    NOT enough

    above limit

    DENIED

     75        reality = src.atm.withdraw(
     76            card_has_expired=True,
     77            pin_is_correct=False,
     78            balance_is_enough=False,
     79            above_daily_limit=False
     80        )
     81        self.assertEqual(reality, my_expectation)
     82
     83        reality = src.atm.withdraw(
     84            card_has_expired=False,
     85            pin_is_correct=True,
     86            balance_is_enough=True,
     87            above_daily_limit=True,
     88        )
     89        self.assertEqual(reality, my_expectation)
     90
     91        reality = src.atm.withdraw(
     92            card_has_expired=False,
     93            pin_is_correct=True,
     94            balance_is_enough=False,
     95            above_daily_limit=True,
     96        )
     97        self.assertEqual(reality, my_expectation)
     98
     99
    100# Exceptions seen
    

    the test is still green

  • I add an assertion for when the card has NOT expired, the right PIN is entered, the balance is NOT enough and the account is below limit for daily withdrawals

    card expired

    PIN

    balance

    daily limit

    withdrawal

    NOT expired

    right PIN

    enough

    above limit

    DENIED

    NOT expired

    right PIN

    enough

    below limit

    CASH

    NOT expired

    right PIN

    NOT enough

    above limit

    DENIED

    NOT expired

    right PIN

    NOT enough

    below limit

    DENIED

     83        reality = src.atm.withdraw(
     84            card_has_expired=False,
     85            pin_is_correct=True,
     86            balance_is_enough=True,
     87            above_daily_limit=True,
     88        )
     89        self.assertEqual(reality, my_expectation)
     90
     91        reality = src.atm.withdraw(
     92            card_has_expired=False,
     93            pin_is_correct=True,
     94            balance_is_enough=False,
     95            above_daily_limit=True,
     96        )
     97        self.assertEqual(reality, my_expectation)
     98
     99        reality = src.atm.withdraw(
    100            card_has_expired=False,
    101            pin_is_correct=True,
    102            balance_is_enough=False,
    103            above_daily_limit=False,
    104        )
    105        self.assertEqual(reality, my_expectation)
    106
    107
    108# Exceptions seen
    

    still green


  • I add an assertion for when the card has NOT expired, the wrong PIN is entered, the balance is enough and the account is above limit for daily withdrawals

    card expired

    PIN

    balance

    daily limit

    withdrawal

    NOT expired

    wrong PIN

    enough

    above limit

    DENIED

     99        reality = src.atm.withdraw(
    100            card_has_expired=False,
    101            pin_is_correct=True,
    102            balance_is_enough=False,
    103            above_daily_limit=False,
    104        )
    105        self.assertEqual(reality, my_expectation)
    106
    107        reality = src.atm.withdraw(
    108            card_has_expired=False,
    109            pin_is_correct=False,
    110            balance_is_enough=True,
    111            above_daily_limit=True,
    112        )
    113        self.assertEqual(reality, my_expectation)
    114
    115
    116# Exceptions seen
    

    green

  • I add the next assertion, where the card has NOT expired, the wrong PIN is entered, the balance is enough and the account is below limit for daily withdrawals

    card expired

    PIN

    balance

    daily limit

    withdrawal

    NOT expired

    wrong PIN

    enough

    above limit

    DENIED

    NOT expired

    wrong PIN

    enough

    below limit

    DENIED

    107        reality = src.atm.withdraw(
    108            card_has_expired=False,
    109            pin_is_correct=False,
    110            balance_is_enough=True,
    111            above_daily_limit=True,
    112        )
    113        self.assertEqual(reality, my_expectation)
    114
    115        reality = src.atm.withdraw(
    116            card_has_expired=False,
    117            pin_is_correct=False,
    118            balance_is_enough=True,
    119            above_daily_limit=False,
    120        )
    121        self.assertEqual(reality, my_expectation)
    122
    123
    124# Exceptions seen
    

    still green

  • I add an assertion for when the card has NOT expired, the wrong PIN is entered, the balance is NOT enough and the account is above limit for daily withdrawals

    card expired

    PIN

    balance

    daily limit

    withdrawal

    NOT expired

    wrong PIN

    enough

    above limit

    DENIED

    NOT expired

    wrong PIN

    enough

    below limit

    DENIED

    NOT expired

    wrong PIN

    NOT enough

    above limit

    DENIED

    107        reality = src.atm.withdraw(
    108            card_has_expired=False,
    109            pin_is_correct=False,
    110            balance_is_enough=True,
    111            above_daily_limit=True,
    112        )
    113        self.assertEqual(reality, my_expectation)
    114
    115        reality = src.atm.withdraw(
    116            card_has_expired=False,
    117            pin_is_correct=False,
    118            balance_is_enough=True,
    119            above_daily_limit=False,
    120        )
    121        self.assertEqual(reality, my_expectation)
    122
    123        reality = src.atm.withdraw(
    124            card_has_expired=False,
    125            pin_is_correct=False,
    126            balance_is_enough=False,
    127            above_daily_limit=True,
    128        )
    129        self.assertEqual(reality, my_expectation)
    130
    131
    132# Exceptions seen
    

    the test is still green

  • I add an assertion for when the card has NOT expired, the wrong PIN is entered, the balance is NOT enough and the account is below limit for daily withdrawals

    card expired

    PIN

    balance

    daily limit

    withdrawal

    NOT expired

    wrong PIN

    enough

    above limit

    DENIED

    NOT expired

    wrong PIN

    enough

    below limit

    DENIED

    NOT expired

    wrong PIN

    NOT enough

    above limit

    DENIED

    NOT expired

    wrong PIN

    NOT enough

    below limit

    DENIED

    107        reality = src.atm.withdraw(
    108            card_has_expired=False,
    109            pin_is_correct=False,
    110            balance_is_enough=True,
    111            above_daily_limit=True,
    112        )
    113        self.assertEqual(reality, my_expectation)
    114
    115        reality = src.atm.withdraw(
    116            card_has_expired=False,
    117            pin_is_correct=False,
    118            balance_is_enough=True,
    119            above_daily_limit=False,
    120        )
    121        self.assertEqual(reality, my_expectation)
    122
    123        reality = src.atm.withdraw(
    124            card_has_expired=False,
    125            pin_is_correct=False,
    126            balance_is_enough=False,
    127            above_daily_limit=True,
    128        )
    129        self.assertEqual(reality, my_expectation)
    130
    131        reality = src.atm.withdraw(
    132            card_has_expired=False,
    133            pin_is_correct=False,
    134            balance_is_enough=False,
    135            above_daily_limit=False,
    136        )
    137        self.assertEqual(reality, my_expectation)
    138
    139
    140# Exceptions seen
    

    still green

  • I remove the reality variables because I do not need them, I can call the show function directly

        def test_atm_withdrawal(self):
            my_expectation = 'CASH'
            self.assertEqual(
                src.atm.withdraw(
                    card_has_expired=False,
                    pin_is_correct=True,
                    balance_is_enough=True,
                    above_daily_limit=False,
                ),
                my_expectation
            )
    
            my_expectation = 'DENIED'
    
            self.assertEqual(
                src.atm.withdraw(
                    card_has_expired=True,
                    pin_is_correct=True,
                    balance_is_enough=True,
                    above_daily_limit=True,
                ),
                my_expectation
            )
    
            self.assertEqual(
                src.atm.withdraw(
                    card_has_expired=True,
                    pin_is_correct=True,
                    balance_is_enough=True,
                    above_daily_limit=False,
                ),
                my_expectation
            )
    
            self.assertEqual(
                src.atm.withdraw(
                    card_has_expired=True,
                    pin_is_correct=True,
                    balance_is_enough=False,
                    above_daily_limit=True,
                ),
                my_expectation
            )
    
            self.assertEqual(
                src.atm.withdraw(
                    card_has_expired=True,
                    pin_is_correct=True,
                    balance_is_enough=False,
                    above_daily_limit=False,
                ),
                my_expectation
            )
    
            self.assertEqual(
                src.atm.withdraw(
                    card_has_expired=True,
                    pin_is_correct=False,
                    balance_is_enough=True,
                    above_daily_limit=True,
                ),
                my_expectation
            )
    
            self.assertEqual(
                src.atm.withdraw(
                    card_has_expired=True,
                    pin_is_correct=False,
                    balance_is_enough=True,
                    above_daily_limit=False,
                ),
                my_expectation
            )
    
            self.assertEqual(
                src.atm.withdraw(
                    card_has_expired=True,
                    pin_is_correct=False,
                    balance_is_enough=False,
                    above_daily_limit=True,
                ),
                my_expectation
            )
    
            self.assertEqual(
                src.atm.withdraw(
                    card_has_expired=True,
                    pin_is_correct=False,
                    balance_is_enough=False,
                    above_daily_limit=False
                ),
                my_expectation
            )
    
            self.assertEqual(
                src.atm.withdraw(
                    card_has_expired=False,
                    pin_is_correct=True,
                    balance_is_enough=True,
                    above_daily_limit=True,
                ),
                my_expectation
            )
    
            self.assertEqual(
                src.atm.withdraw(
                    card_has_expired=False,
                    pin_is_correct=True,
                    balance_is_enough=False,
                    above_daily_limit=True,
                ),
                my_expectation
            )
    
            self.assertEqual(
                src.atm.withdraw(
                    card_has_expired=False,
                    pin_is_correct=True,
                    balance_is_enough=False,
                    above_daily_limit=False,
                ),
                my_expectation
            )
    
            self.assertEqual(
                src.atm.withdraw(
                    card_has_expired=False,
                    pin_is_correct=False,
                    balance_is_enough=True,
                    above_daily_limit=True,
                ),
                my_expectation
            )
    
            self.assertEqual(
                src.atm.withdraw(
                    card_has_expired=False,
                    pin_is_correct=False,
                    balance_is_enough=True,
                    above_daily_limit=False,
                ),
                my_expectation
            )
    
            self.assertEqual(
                src.atm.withdraw(
                    card_has_expired=False,
                    pin_is_correct=False,
                    balance_is_enough=False,
                    above_daily_limit=True,
                ),
                my_expectation
            )
    
            self.assertEqual(
                src.atm.withdraw(
                    card_has_expired=False,
                    pin_is_correct=False,
                    balance_is_enough=False,
                    above_daily_limit=False,
                ),
                my_expectation
            )
    
    
    # Exceptions seen
    

close the project

  • I close test_atm.py and atm.py in the editor

  • I click in the terminal, then use q on the keyboard to leave the tests. The terminal goes back to the command line

  • I change directory to the parent of atm

    cd ..
    

    the terminal is my friend, and shows

    .../pumping_python
    

    I am back in the pumping_python directory


review

I ran tests for an Automatic Teller Machine with the following inputs:

  • has the card expired?

  • is the PIN correct?

  • is the requested amount smaller or bigger than what is in the account?

  • will this put the account above or below the daily limit for withdrawals?

the inputs gave me this truth table

card expired

PIN

balance

daily limit

withdrawal

expired

right PIN

enough

above limit

DENIED

expired

right PIN

enough

below limit

DENIED

expired

right PIN

NOT enough

above limit

DENIED

expired

right PIN

NOT enough

below limit

DENIED

expired

wrong PIN

enough

above limit

DENIED

expired

wrong PIN

enough

below limit

DENIED

expired

wrong PIN

NOT enough

above limit

DENIED

expired

wrong PIN

NOT enough

below limit

DENIED

card expired

PIN

balance

daily limit

withdrawal

NOT expired

right PIN

enough

above limit

DENIED

NOT expired

right PIN

enough

below limit

CASH

NOT expired

right PIN

NOT enough

above limit

DENIED

NOT expired

right PIN

NOT enough

below limit

DENIED

NOT expired

wrong PIN

enough

above limit

DENIED

NOT expired

wrong PIN

enough

below limit

DENIED

NOT expired

wrong PIN

NOT enough

above limit

DENIED

NOT expired

wrong PIN

NOT enough

below limit

DENIED

What if I want the ATM to give a different message with each denial, so that the user knows why the withdrawal failed? The truth table could then be

card expired

PIN

balance

daily limit

withdrawal

expired

right PIN

enough

above limit

DENIED: Card Expired

expired

right PIN

enough

below limit

DENIED: Card Expired

expired

right PIN

NOT enough

above limit

DENIED: Card Expired

expired

right PIN

NOT enough

below limit

DENIED: Card Expired

expired

wrong PIN

enough

above limit

DENIED: Card Expired

expired

wrong PIN

enough

below limit

DENIED: Card Expired

expired

wrong PIN

NOT enough

above limit

DENIED: Card Expired

expired

wrong PIN

NOT enough

below limit

DENIED: Card Expired

card expired

PIN

balance

daily limit

withdrawal

NOT expired

right PIN

enough

above limit

DENIED: You have exceeded the daily withdrawal Limit

NOT expired

right PIN

enough

below limit

CASH

NOT expired

right PIN

NOT enough

above limit

DENIED: There is not enough money in the account to complete the withdrawal

NOT expired

right PIN

NOT enough

below limit

DENIED: There is not enough money in the account to complete the withdrawal

NOT expired

wrong PIN

enough

above limit

Error: You entered the wrong PIN. Try again

NOT expired

wrong PIN

enough

below limit

Error: You entered the wrong PIN. Try again

NOT expired

wrong PIN

NOT enough

above limit

Error: You entered the wrong PIN. Try again

NOT expired

wrong PIN

NOT enough

below limit

Error: You entered the wrong PIN. Try again


code from the chapter

Do you want to see all the CODE I typed in this chapter?


what is next?

you now know

Would you like to test making a calculator?


rate pumping python

If this has been a 7 star experience for you, please CLICK HERE to leave a 5 star review of pumping python. It helps other people get into the book too