Is there a way to simultaneously test two or more assertion in pytest test cases

Viewed 61

I have a test case written in selenium python such as the following

This is a test case written in pytest

def test_calculations():
   a = 5
   b = 6
   assert a+b == 10,"addition error"
   assert a-b == -1,"subtraction error" 

now i want a way such that when i run this test both of these assertions should be performed regard less of the previous assertion being failed and then provide specific result for specific assertion

2 Answers

Just wrap every assert in a try except block:

def test_calculations():
    a = 5
    b = 6
    try:
        assert a + b == 10, 'addition error'
    except AssertionError:
        print('Addition error')
    try:    
        assert a - b == -1, 'subtraction error'
    except AssertionError:
        print('subtraction error')

You can put those two tests in a tuple like in metatoaster's comment. But I will first clarify:

  1. It should be clear you can't "test everything simultaneously".
  2. Tests are meant to stop at the first failure. Consider what would happen if PyTest didn't behave like that an instead always proceeded - any "real" failure would be followed by more failures which have nothing to do with the code being tested. Example:
    obj = MyClass()  # returns None
    assert obj is not None  # PyTest should fail here
                            # but imagine if it behaves how you wanted
    assert obj.do_action() == 10  # AttributeError: 'NoneType' object has no attribute 'do_action'
    
    • In your case for Selenium, if there was a button = driver.get_element... and the assert button is not None failed, your next step for button.click() would still fail. So it's better for Pytest to stop after a failure.
  3. Things which you want to test independently should be individual tests or Iterations of a test.

If you want two checks to run independently of each other, then put them as individual iterations with parametrize. Each iteration runs independently of the previous, so each check can run as its own test.

import operator
import pytest

testdata = [
    (operator.add, 10),
    (operator.sub, -1),
]

@pytest.mark.parametrize("operation,expected", testdata)
def test_each_operation(operation, expected):
    a = 5  # these should actually be in the test data
    b = 6
    assert operation(a, b) == expected

Result, note the "1 failed, 1 passed" below:

=========================== short test summary info ===========================
FAILED pytest_iterations.py::test_each_operation[add-10] - assert 11 == 10
========================= 1 failed, 1 passed in 0.04s =========================

Better layout:

import operator
import pytest

testdata = [
    (5, 6, operator.add, 10),    # fail
    (5, 6, operator.sub, -1),    # pass
    (5, 10, operator.mul, 100),  # fail
    (5, 10, operator.mul, 50),   # pass
]

@pytest.mark.parametrize("a,b,operation,expected", testdata)
def test_each_operation(a, b, operation, expected):
    assert operation(a, b) == expected

Result: 2 failed, 2 passed:

=========================== short test summary info ===========================
FAILED pytest_iterations.py::test_each_operation[5-6-add-10] - assert 11 == 10
FAILED pytest_iterations.py::test_each_operation[5-10-mul-100] - assert 50 ==...
========================= 2 failed, 2 passed in 0.04s =========================
Related