test_if_else

test_if_else(index=1, test=None, body=None, orelse=None, expand_message=True, use_if_exp=False, state=None)

Test parts of the if statement.

This test function will allow you to extract parts of a specific if statement and perform a set of tests specifically on these parts. A for loop consists of three potential parts: the condition test, test, which specifies the condition of the if statement, the body, which is what’s executed if the condition is True and a else part, orelse, which will be executed if the condition is not True.:

if 5 == 3:
    print("success")
else:
    print("fail")

Has 5 == 3 as the condition test, print("success") as the body and print("fail") as the else part.

Parameters:
  • index (int) – index of the function call to be checked. Defaults to 1.
  • test – this argument holds the part of code that will be ran to check the condition test of the if statement. It should be passed as a lambda expression or a function definition. The functions that are ran should be other pythonwhat test functions, and they will be tested specifically on only the condition test of the if statement.
  • body – this argument holds the part of code that will be ran to check the body of the if statement. It should be passed as a lambda expression or a function definition. The functions that are ran should be other pythonwhat test functions, and they will be tested specifically on only the body of the if statement.
  • orelse – this argument holds the part of code that will be ran to check the else part of the if statement. It should be passed as a lambda expression or a function definition. The functions that are ran should be other pythonwhat test functions, and they will be tested specifically on only the else part of the if statement.
  • expand_message (bool) – if true, feedback messages will be expanded with in the ___ of the if statement on line ___. Defaults to True. If False, test_if_else() will generate no extra feedback.
Example:

Student code:

a = 12
if a > 3:
    print('test %d' % a)

Solution code:

a = 4
if a > 3:
    print('test %d' % a)

SCT:

test_if_else(1,
    body = test_expression_output(
            extra_env = { 'a': 5 }
            incorrect_msg = "Print out the correct things"))

This SCT will pass as test_expression_output() is ran on the body of the if statement and it will output the same thing in the solution as in the student code.

test_if_else(index=1,
             test=None,
             body=None,
             orelse=None,
             expand_message=True)

test_if_else() allows you to robustly check if statements, optionally extended with elif and else components. For each of the components of an if-else construct test_if_else() takes several ‘sub-SCTs’. These ‘sub-SCTs’, that you have to pass in the form of lambda functions or through a function that defines all tests, are executed on these separate parts of the submission.

Example 1

Suppose an exercise asks the student to code up the following if-else construct:

*** =solution
```{python}
# a is set to 5
a = 5

# If a < 5, print out "It's small", else print out "It's big"
if a < 5:

else:
  print("It's big")
```

The if-else construct here consists of three parts:

  • The condition to check: a < 5. The test argument of test_if_else() specifies the sub-SCT to test this.
  • The body of the if statement: print("It's small"). The body argument of test_if_else() specifies the sub-SCT to test this.
  • The else part: print("It's big"). The orelse argument of test_if_else() specifies the sub-SCT to ttest this.

You can thus write our SCT as follows. Notice that for the test argument a function is used to specify different tests; for the body and orelse arguments two lambda functions suffise.

*** =sct
```{python}
def sct_on_condition_test():
  test_expression_result({"a": 4})
  test_expression_result({"a": 5})
  test_expression_result({"a": 6})

test_if_else(index = 1,
             test = sct_on_condition_test,
             body = lambda: test_function("print")
             orelse = lambda: test_function("print"))
```

The test part

Have a look at the sct_on_condition_test(), that is used to specify the sub-SCT for the test part of the if-else-construct, so a < 5. It contains three calls of the test_expression_result function. These functions are executed in a ‘narrow scope’ that only considers the condition of the student code, and the condition of the solution code.

More specifically, test_expression_result({"a": 5}) will check whether executing the if condition that the student coded when a equals 5 leads to the same result as executing the if condition that is coded in the solution when a equals 5. That way, you can robustly check the validity of the if test. There are three test_expression_result() calls to see if the condition makes sense for different inputs.

Suppose that the student incorrectly used the condition a < 6 instead of a < 5. test_expression_result({"a": 5}) will see what the result is of a < 6 if a equals 5. The result is True. Next, it checks the result of a < 5, the if condition of the solution, which is False. There is a mismatch between the ‘student result’ and the ‘solution result’, and a meaningful feedback messages is generated.

The body and orelse parts

In a similar way, the functions that are used as lambda functions in both the body and orelse part, will also be executed in a ‘narrow scope’, where only the body and orelse part of the student’s submission and the solution are used.