pythontest automation

Python for test automation: operators

Operators in programming are symbols or special characters that perform operations on variables or values. Python supports a variety of operators, including arithmetic operators such as addition (+), subtraction (-), multiplication (*), division (/), and modulus (%); comparison operators such as equal to (==), not equal to (!=), greater than (>), less than (<), greater than or equal to (>=), and less than or equal to (<=); logical operators such as and, or, and not; assignment operators such as =, +=, -=, *=, and /=; bitwise operators such as &, |, ^, ~, <<, and >>; and more. These operators enable us to perform mathematical calculations, compare values, combine conditions, assign values to variables, and manipulate bits, among other tasks.

In this article we'll focus on some of the most used operators used in test automation code.

Arithmetic operators (+, -, *, /, // and %)

+ is simply addition, mostly useful for numbers, but can also be used for strings, lists and tuples, resulting in the two strings/lists/tuples being concatenated.

# addition
print(1 + 1)
>>>2
print("hello " + "there")
>>>hello there
print([1, 2] + [3, 4])
>>>[1, 2, 3, 4]
print((1, 2) + (3, 4))
>>>(1, 2, 3, 4)

- is subtraction, mostly useful for numbers, sets and custom objects. How it works is straightforward for numbers, for sets subtraction means difference, i.e. what elements of s1 are absent from s2 when subtracting s1 - s2.

# subtraction
print(2 - 1)
>>>1
s1 = {1, 2}
s2 = {2, 3}
print(s1 - s2)
>>>{1}
print(s2 - s1)
>>>{3}

* is multiplication, mostly useful for numbers or multiplying strings/lists/tuples by an integer to create Let's take a look at a few examples:

# multiplication
print(2 * 2)
>>>4
print("hello" * 2)
>>>hellohello
print([1, 2] * 2)
>>>[1, 2, 1, 2]
print((3, 4) * 2)
>>>(3, 4, 3, 4)

/ is division including decimal portion, i.e. result will always be a float even when dividing two integers. // is division excluding decimal portion, i.e. result will always exclude any decimal portion of a number.

print(3 / 2)
>>>1
print(3 // 2)
>>>1.5

% is the modulo operator; it can be used to get the remainder of a division operation:

print(5 % 2)
>>>1  # 5 - 2 - 2 = 1

Comparison operators

Comparison operators are essential for verifying the expected behavior of software systems. These operators allow us to compare actual outcomes or results against expected values or conditions, determining whether a test case passes or fails. For example, we can use comparison operators to check if a calculated result matches an expected value, if an element is displayed on a web page, or if a specific error message is shown in response to a user action.

Equal and not equal (== and !=)

In Python, data types can be compared for equality (or not equality) using the == and != operators.

1 == 1  # True
1 != 1  # False
"hello" == "hello"  # True
"hello" == "hi"     # False
1.0 == 2.0  # False
True == True  # True

Equality is straightforward when comparing strings, integers, floats and booleans: only the same value will evaluate equality comparison to True.

The equality operator can also be used for lists, tuples, sets and dicts.

  • Two lists are equal only if they have the same elements in the same order.
  • Two tuples are equal only if they have the same elements in the same order.
  • Two sets are equal only if they contain the same elements.
  • Two dicts are equal only if they contain the same key-value pairs.

Sometimes we want to consider two lists equal if they have the same elements, not in any specific order. This is where sorting (putting the elements of the list in a specific order based on some logic) the lists is necessary.

Order operators (<, <=, >, >=)

In Python data types can be compared for order with the <, <=, > and >= operators. How comparison works depends on the data type:

  • For numbers < evaluates to True if the number on the left side is less than the number on the right side.
  • For strings < evaluates to True if the string on the left side is alphabetically before the string on the right side.
  • For booleans < evaluates to True if the left side is False and right side is True

For other data types such as lists, tuples, sets we need to have a closer look.

For lists and tuples, we go through each element of the lists or tuples in order, and evaluate < on a per element basis. Let's take a look at an example to make it clearer:

l1 = [1, 2, 3]
l2 = [1, 3, 3]
print(l1 < l2)
>>>True

Here l1 < l2 evaluates to True, because we first check the elements in both lists at index one, i.e. we compare 1 < 1, since they are equal, we cannot yet say whether l1 < l2, so we move to the next index (1), to check the next elements: 2 < 3. Since this evaluates to True, we evaluate the l1 < l2 as True. We move to the next index until the comparison evaluates to True, or we run out of elements to compare ultimately evaluating to False.

For sets, order operators determine subset or superset relationships. Because sets are inherently not ordered, we cannot compare elements in two sets 'in order' as with lists and tuples. A set s1 is a subset of s2 if all elements in s1 are present in s2. Let's take a look at a few examples:

s1 = {1, 2}
s2 = {3, 2, 1}
print(s1 < s2)
>>>True  # s2 contains both 1 and 2, therefore s1 is a subset of s2
s1 = {1, 2, 3}
s2 = {3, 1, 2}
print(s1 < s2)
>>>False  # s1 is not a subset of s2, they are equal
print(s1 <= s2)
>>>True  # s1 is a subset of s2 OR equal to s2

s1 < s2 evaluates to True, if all elements in s1 are present in s2, but they are not the same set. s1 <= s2 evaluates to True if s1 is a subset of s2 or they are the same set. > and >= are the same comparisons the other way around (s1 < s2 is equal to s2 > s1).

For dicts, we cannot direcly compare two dictionaries with the order operators. However, we can still make a subset and superset comparison of two dictionaries if we compare the items of two dicts. The items of a dictionary is a list of tuples containing the key-value pairs of the dict; each tuple in the set contains two values in order: (, ). For comparision we can think of the items as sets of tuples.

d1 = {"a": 1, "b": 2}
d2 = {"c": 3, "b": 2, "a": 1}
print(d1.items() < d2.items())
>>>True  # d1 items are a subset of d2
print(d1.items() <= d2.items())
>>>True  # d1 items are subset of d2 OR equal to d2

Logical operators (and, or, not)

and

The logical operator "and" is used to combine two conditional expressions and evaluate to True only if both expressions are true. If either or both of the expressions evaluate to False, the "and" operator returns False. It is often used in conjunction with conditional statements or boolean expressions to create compound conditions. For example, in an "if" statement, the "and" operator allows us to specify multiple conditions that must all be true for the code block to be executed. The "and" operator short-circuits, meaning that if the first expression evaluates to False, the second expression is not evaluated, as the overall result will always be False. This behavior can improve performance and efficiency in cases where the second expression involves costly operations or function calls.

x = 10
if x > 5 and x < 20:
    print("x is between 5 and 20")
>>>x is between 5 and 20

or

The logical operator "or" is used to combine two conditional expressions and evaluate to True if at least one of the expressions is true. If both expressions evaluate to False, the "or" operator returns False. This operator is commonly used in conditional statements to create compound conditions where any of the individual conditions being true is sufficient for the overall condition to be true. Similar to the "and" operator, the "or" operator also short-circuits, meaning that if the first expression evaluates to True, the second expression is not evaluated, as the overall result will always be True. This behavior can improve performance and efficiency, especially when the second expression involves costly operations or function calls.

x = 10
if x < 0 or x % 2 == 0:  # 10 < 0 evaluates to false,
                         # 10 % 2 == 0 evaluates to True
    print("x is negative or even")

not

The logical operator "not" is a unary operator used to negate the value of a boolean expression. When applied to a boolean value or expression, the "not" operator returns True if the expression evaluates to False, and False if the expression evaluates to True. It essentially flips the truth value of the expression. The "not" operator is commonly used to invert conditions or boolean values in conditional statements, making it useful for expressing negation or performing logical negation. For example, "not True" evaluates to False, and "not x > 5" evaluates to True if x is less than or equal to 5, basically the same as "not x > 5" is the same as "x <= 5".