Pages

Saturday 15 April 2023

pytest in python by example

Pytest is a popular testing framework in Python that makes it easy to write and run tests for your code.


Testing a Function:

def add_numbers(a, b):

return a + b


def test_add_numbers():

assert add_numbers(2, 3) == 5

assert add_numbers(5, 7) == 12

Testing an Object Method:

class Person:

def __init__(self, name, age):

self.name = name

self.age = age

def say_hello(self):

return f"Hello, my name is {self.name} and I am {self.age} years old."


def test_say_hello():

person = Person("John", 30)

assert person.say_hello() == "Hello, my name is John and I am 30 years old."

Testing an Exception:

def divide_numbers(a, b):

if b == 0:

raise ValueError("Cannot divide by zero")

return a / b


def test_divide_numbers():

with pytest.raises(ValueError):

divide_numbers(10, 0)

Testing for Expected Output:

def square_number(x):

return x * x


def test_square_number():

assert square_number(2) == 4

assert square_number(5) == 25

Testing for Unexpected Output:

def is_even_number(x):

return x % 2 == 0


def test_is_even_number():

assert is_even_number(4) == True

assert is_even_number(7) == False

Testing Multiple Inputs:

def add_numbers(a, b):

return a + b


@pytest.mark.parametrize("a,b,result", [(2, 3, 5), (5, 7, 12)])

def test_add_numbers(a, b, result):

assert add_numbers(a, b) == result

Testing Output Using Fixtures:

import pytest
class Person:
  def __init__(self, name, age):
    self.name = name
    self.age = age

  def say_hello(self):
     	return f"Hello, my name is {self.name} and I am {self.age} years old."
  
@pytest.fixture
def get_person():
  person = Person("John", 30)
  return person

def test_say_hello(get_person):
    assert get_person.say_hello() == "Hello, my name is John and I am 30 years old."

Skipping Tests:

@pytest.mark.skip(reason="Not implemented yet")

def test_function():

assert False

Marking Tests as Expected to Fail:

@pytest.mark.xfail

def test_function():

assert False

Using Hooks:

def pytest_runtest_setup(item):
	print("Running test setup")
    def pytest_runtest_teardown(item):
    	print("Running test teardown")
    def test_function():
    	assert True

Testing Using Mocks:

from unittest.mock import Mock

def test_function(mocker):

mock_function = Mock(return_value=True)

mocker.patch("module.function", mock_function)

assert module.function() == True

mock_function.assert_called_once()

Testing Using Fixtures with Parameters:

@pytest.fixture(params=[(2, 3), (5, 7)])

def get_numbers(request):

return request.param


def test_add_numbers(get_numbers):

a, b = get_numbers

assert a + b == add_numbers(a, b)

Testing for Expected Warnings:

import warnings


def test_function():

with warnings.catch_warnings(record=True) as w:

warnings.warn("Warning message")

assert len(w) == 1

assert issubclass(w[-1].category, UserWarning)

assert "Warning message" in str(w[-1].message)

Testing Using Temp Files:

import tempfile


def test_function():

with tempfile.TemporaryFile() as tmp_file:

tmp_file.write(b"test content")

tmp_file.seek(0)

assert tmp_file.read() == b"test content"

Testing for Performance:

import time


def test_function():

start_time = time.time()

# Code to be timed

elapsed_time = time.time() - start_time

assert elapsed_time < 1.0

Testing Using Test Classes:

class TestClass:

def test_function(self):

assert add_numbers(2, 3) == 5


def test_another_function(self):

assert square_number(5) == 25

Testing for Expected Exceptions with Messages:

def test_function():

with pytest.raises(ValueError, match=r".*divide by zero.*"):

divide_numbers(10, 0)

Testing for Object Equality:

def test_function():

assert Person("John", 30) == Person("John", 30)

Testing for Object Inequality:

def test_function():

assert Person("John", 30) != Person("Jane", 25)

Testing Using Subtests:

def test_function():

for i in range(5):

with subtests.test(msg=f"Test with i={i}"):

assert i % 2 == 0

These are just a few more examples of what Pytest can do. There are many more features and ways to use the framework depending on your specific testing needs.

Here are some of the advantages of using pytest:

Simple syntax: Pytest has a simple and intuitive syntax that makes it easy to write and read tests. It uses assert statements to check whether the test passes or fails, and provides clear error messages when tests fail.

Fixture system: Pytest provides a fixture system that allows you to set up and tear down resources for your tests. Fixtures are functions that are called before and/or after your tests to provide a clean testing environment.

Parametrization: Pytest allows you to write parametrized tests, which can run the same test with different input values. This can save time and reduce code duplication when testing similar functions.

Integration with other tools: Pytest can integrate with other testing and development tools, such as coverage analysis, code profiling, and continuous integration systems.

Plugins: Pytest has a large ecosystem of plugins that can extend its functionality, such as plugins for testing Django applications, generating test reports, and mocking.

Overall, pytest is a flexible and powerful testing framework that can help you write and run tests more efficiently and effectively.

No comments:

Post a Comment