Abhinav Manthri
Abhinav Manthri

Reputation: 348

Python Mock: raise 3rd party exception for unit testing

Let's say i have a method is_validate, which internally calls validate method from library gateway.service

import gateway.service
from gateway.service.exception import ValidatorException

def is_validate():
   try:
       gateway.service.validate() # which throws ValidatorException
       return True
   except ValidatorException ex:
       return False

How to unit test is_validate method, mocking gateway.service.validate to throw ValidatorException ?

Upvotes: 1

Views: 1250

Answers (2)

Abhinav Manthri
Abhinav Manthri

Reputation: 348

-------------------------------------
mymodule.py
-------------------------------------

import os
def remove(file_path):
    if os.path.exists(file_path):
        os.remove(file_path)
    else:
        print('File does not exist')

-------------------------------------

from mymodule import remove
import mock
import unittest
class RemoveTestCase(unittest.TestCase):
    
    @mock.patch('mymodule.os.path')
    @mock.patch('mymodule.os.remove')
    def test_remove(self, mock_os_remove, mock_os_path):
        mock_os_path.exists.return_value = True
#side_effect
        remove("any path")
        mock_os_remove.assert_called_with("any path")

I was able to mock gateway.service.validate by referencing it with module name where is_validate method is present.

ex: @mock.patch('mymodule.gateway.service.validate')

Reference this doc for more info

Upvotes: 0

baileythegreen
baileythegreen

Reputation: 1194

You can do this with a combination of:

  • mocking a function (creating a fake version of the function dictating what it returns);
  • monkeypatching the actual function with your mock version;
  • and using pytest to actually run the test.

I've written a description of how to do this (pulled from my own work) here, in case an example I know works is useful.

But this is what I think you'll need to do in your code:

Define a pytest fixture to mock the scenario you want to test, using monkeypatch to fake the results you want from the parts of the is_validate().

And a test to check that a ValidatorException is raised; the code that raises the error in the test is in the pytest fixture. The entire pytest fixture defined there is passed as a parameter to the test.

import pytest
from unittest import TestCase

import gateway.service
from gateway.service.exception import ValidatorException


# Create object for accessing unittest assertions
assertions = TestCase("__init__")


@pytest.fixture
def validation_fails(monkeypatch):
    """
    Mocks a call to gateway.service.validate().
    """

    def mock_validate(*args, **kwargs):
        """Mock an absolute file path."""
        raise ValidatorException

    # Replace calls to existing methods with the mocked versions
    monkeypatch.setattr(gateway.service, "validate", mock_validate)


def test_validation_fails(validation_fails):
    """Test validation."""

    # check that the correct exception is raised
    with assertions.assertRaises(ValidatorException):
        is_validate()

Note: This does not include whatever setup is required to get pytest working for your project.

Upvotes: 1

Related Questions