Skip to main content

Use this tool to develop unit tests which obtain complete coverage.

Project description

simcm 2.0.1

simcm.Simulate is a context manager which can simulate responses from external resources.

Use this tool to develop unit tests which obtain complete coverage without using the external resource.

While testing there is often a need to simulate the reponses of calls to external resources. Perhaps the resource is not available in the test environment, or there is code which handles exceptional cases which cannot be triggered on demand.

A good strategy is to implement subordinate methods so they can be tested in isolation. Even so, the context required to test a particular method may be difficult to arrange.

In these cases, a simulator which simulates the response is simpler to use because it lets the application run as is and handle the (supposedly) actual response.

DESCRIPTION

Simulate a series of calls to a function with a list of mocked responses.

The Simulate class is a context manager. On __enter__, the target function is replaced with simulate On __exit__, the target function is restored.

with Simulate(
        target_string,
        target_globals,
        response_list):
    test_the_application()
  • target_string: The function to simulate, passed as a string.
  • target_globals: A dict used to resolve any global references in target_string.
  • response_list: The list of responses that simulate will return. Each element of the list is either a callable (typically the target, passed as a function) or a mocked response.

The elements of the response_list are put onto a FIFO queue. simulate reads the next element from the queue. If the element is callable, it is called with all the arguments the application had passed to the target, and the result is returned; otherwise the element is returned.

There are two events to consider.

  1. simulate is called, but there is no next element. In this case, queue_empty_on_simulate(*args, **kwargs) is called. queue_empty_on_simulate raises QueueEmptyError. As an aid in preparing the response_list, args and kwargs are included in the exception message.

  2. __exit__ is called, but elements remain in the queue. In this case, queue_not_empty_on_exit(exception_type, exception_value, traceback) is called. queue_not_empty_on_exit raises QueueNotEmptyError. As an aid in preparing the response_list, the number of elements remaining in the queue is included in the exception message.

Both exceptions are sub-classes of SimulateError.

To change this behavior, sub-class Simulate, and overwrite these methods. If queue_empty_on_simulate returns, it should return a callable or a mocked response.

EXAMPLE

When the test is run, the first GET request is sent and the actual response is returned. The second GET request is not sent, the MockedResponse is returned instead.

my_app.py

import requests

def my_app():
    response1 = requests.request(
            method='GET',
            url='https://pypi.org')
    if response1.status_code == 200:
        response2 = requests.request(
                method='GET',
                url='http://google.com')
        if reponse2.status_code == 500:
            raise RuntimeError('Google 500')
    else:
        raise RuntimeError('Pypi not 200')

test_my_app.py

import pytest
import requests
import simcm

import my_app

class MockedResponse:
    def __init__(self, status_code, text):
        self.status_code = status_code
        self.text=text

def test_my_app_google_500():
    with pytest.raises(RuntimeError) as exc: 
        with simcm.Simulate(
                target_string='requests.request',
                target_globals=dict(requests=requests),
                response_list=[
                        requests.request,
                        MockedResponse(status_code=500, text='')]):
            my_app.my_app()
    result = str(exc.value)
    expect = 'Google 500'
    assert result == expect, f'result: {result}'

CLASSES

    builtins.Exception(builtins.BaseException)
        SimulateError
            QueueEmptyError
            QueueNotEmptyError
    builtins.object
        Simulate
    
    class QueueEmptyError(SimulateError)
     |  queue empty
     |  
     |  Method resolution order:
     |      QueueEmptyError
     |      SimulateError
     |      builtins.Exception
     |      builtins.BaseException
     |      builtins.object
     |  
    class QueueNotEmptyError(SimulateError)
     |  queue not empty
     |  
     |  Method resolution order:
     |      QueueNotEmptyError
     |      SimulateError
     |      builtins.Exception
     |      builtins.BaseException
     |      builtins.object
     |  
    class Simulate(builtins.object)
     |  Simulate(target_string: str, target_globals: dict, response_list: list = None)
     |  
     |  Create a context which replaces the target callable
     |  with self.simulate.
     |  
     |  Methods defined here:
     |  
     |  __enter__(self)
     |      Save target.
     |      Replace target with self.simulate.
     |      Return self.
     |  
     |  __exit__(self, exception_type, exception_value, traceback)
     |      Restore target.
     |      Call queue_not_empty_on_exit if the queue is not empty.
     |  
     |  __init__(self, target_string: str, target_globals: dict, response_list: list = None)
     |      Initialize self.  See help(type(self)) for accurate signature.
     |  
     |  enqueue(self, response_list=None)
     |      Put response_list items onto self.queue.
     |      Default is self.response_list.
     |  
     |  queue_empty_on_simulate(self, *args, **kwargs)
     |      What to do when the queue is empty
     |      and simulate is called.
     |      Raise QueueEmptyError.
     |  
     |  queue_not_empty_on_exit(self, exception_type, exception_value, traceback)
     |      What to do when the queue is not empty on exit.
     |      Raise QueueNotEmptyError.
     |  
     |  simulate(self, *args, **kwargs)
     |      Interpret the next response.
     |      If it is callable, call it, and return the result;
     |      otherwise return it.
     |  
     |  ----------------------------------------------------------------------
    class SimulateError(builtins.Exception)
     |  base error
     |  
     |  Method resolution order:
     |      SimulateError
     |      builtins.Exception
     |      builtins.BaseException
     |      builtins.object
     |  

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

simcm-2.0.1.tar.gz (5.5 kB view details)

Uploaded Source

File details

Details for the file simcm-2.0.1.tar.gz.

File metadata

  • Download URL: simcm-2.0.1.tar.gz
  • Upload date:
  • Size: 5.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.22.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.8.10

File hashes

Hashes for simcm-2.0.1.tar.gz
Algorithm Hash digest
SHA256 378cbfab67ae3a790a3142ca3d141eecb6dfd01301bc9a3412bedf822cc65282
MD5 0c3ce2b5c15c9a376c61d961e1dfaf5a
BLAKE2b-256 a3034ef5504085271513303810984c82c9897ba39b0dad07df8416f3d336a577

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page