Subhayan Bhattacharya
Subhayan Bhattacharya

Reputation: 5723

How to check for False value returned from a function using pytest

I have the below Python function code :

class ValidateHotelStars(AbsValidator):
    @staticmethod
    def validate(stars):
        try:
            star = int(stars)
            if star < 0 or star > 5:
                return False
            else:
                return True
        except ValueError:
            return False

Now i am trying to write a unit test for this function using pytest :

def test_star_value_less_than_zero():
    invalid_stars = [-5, 4, "Five"]
    assert not all(list(map(ValidateHotelStars.validate, invalid_stars)))

Now this passes with the below output :

(venv) C:\Users\SUSUBHAT.ORADEV\PycharmProjects\hoteldatareader>python -m pytest
============================= test session starts =============================
platform win32 -- Python 3.6.5, pytest-3.9.1, py-1.7.0, pluggy-0.8.0
rootdir: C:\Users\SUSUBHAT.ORADEV\PycharmProjects\hoteldatareader, inifile:
collected 1 item

hoteldatareader\tests\test_validators.py .                               [100%]

========================== 1 passed in 0.31 seconds ===========================

This should ideally fail right since when i run this from the Python REPL:

>>> from hoteldatareader.fieldvalidators.validate_hotel_stars import ValidateHotelStars
>>> invalid_stars = [-5, 4, "Five"]
>>> list(map(ValidateHotelStars.validate, invalid_stars))
[False, True, False]

So not all of them are False .

I think the syntax of my test is not correct.

Can someone please correct me here .

Many thanks

Upvotes: 3

Views: 8703

Answers (3)

hoefling
hoefling

Reputation: 66461

While the answers do give an insight about how to test a list of booleans containing only True values, they all miss the essential stuff:

Basically, you are doing three tests in one. This approach has many disadvantages - what if ValidateHotelStars.validate raises an unhandled exception in the middle of the stars list? The test will fail and the remaining stars won't be checked. Assuming assert not any(...) fails - can you say which of the star arguments was the failure reason? All you get is an AssertionError: False is not true, without giving you any insight into the exact the error source.

Since you already use pytest, why not use one its strong features? Parametrize the test:

import pytest

@pytest.mark.parametrize('invalid_star', [-5, 4, "Five"])
def test_invalid_star_is_not_validated(invalid_star):
    assert not ValidateHotelStars.validate(invalid_star)

Running the test will yield:

$ pytest -v
================================== test session starts ===================================
platform darwin -- Python 3.6.6, pytest-3.9.1, py-1.5.4, pluggy-0.7.1
cachedir: .pytest_cache
rootdir: /Users/hoefling/projects/private/stackoverflow, inifile:
collected 3 items

test_spam.py::test_invalid_star_is_not_validated[-5] PASSED                        [ 33%]
test_spam.py::test_invalid_star_is_not_validated[4] FAILED                         [ 66%]
test_spam.py::test_invalid_star_is_not_validated[Five] PASSED                      [100%]

======================================== FAILURES ========================================
_________________________ test_invalid_star_is_not_validated[4] __________________________

invalid_star = 4

    @pytest.mark.parametrize('invalid_star', [-5, 4, "Five"])
    def test_invalid_star_is_not_validated(invalid_star):
>       assert not ValidateHotelStars.validate(invalid_star)
E       assert not True
E        +  where True = <function ValidateHotelStars.validate at 0x1057936a8>(4)
E        +    where <function ValidateHotelStars.validate at 0x1057936a8> = ValidateHotelStars.validate

test_spam.py:19: AssertionError
=========================== 1 failed, 2 passed in 0.12 seconds ===========================

I had to write only one test, but due to parametrization, pytest will run it three times, each time with a different invalid_star argument. Now, even though 4 fails the test, it will still continue execution with "Five". After the test run finishes, you can immediately see what exact arguments fail what tests. You won't be able to achieve this level of details by looping the list of arguments in a single test.

Upvotes: 3

nikhilesh_koshti
nikhilesh_koshti

Reputation: 403

Use the following check

   list1 = [False, True, False] 
   bool(False in list1)

Upvotes: -1

Stephen Rauch
Stephen Rauch

Reputation: 49812

If you want to check for all False you need:

not any(...)

Test Code:

assert not any([False, True, False])

Results:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

Upvotes: 1

Related Questions