Skip to main content

Mocks that whitelist its interface

Project description

Build Status Coverage Status Code Health PyPI Version

Sealed Mock

Whitelist the attributes/methods of your mocks instead of just letting it create new mock objects.

sealedmock allows to specify when you are done defining the mock, ensuring that any unexpected call to the mock is cached.

Sample:

from unittest.mock import Mock
from sealedmock import seal
m = Mock()
m.method1.return_value.attr1.method2.return_value = 1
seal(m)  # No new attributes can be declared
m.method1().attr1.method2()
# 1
m.method1().attr2
# Exception: AttributeError mock.method1().attr2

Big news! This is getting into Python3.7! See this PR.

Install

pip install sealedmock

Usage

Given you have a file like:

import urllib2

class SampleCodeClass(object):
    """This is sample code"""
    def calling_urlopen(self):
        return urllib2.urlopen("http://chooserandom.com")

    def calling_splithost(self):
        return urllib2.splithost("//host:port/path")

You can write a test like:

from unittest.mock import patch
from sealedmock import seal
@patch("tests.sample_code.urllib2")
def test_using_decorator(mock):
        sample = sample_code.SampleCodeClass()
        mock.urlopen.return_value = 2

        seal(mock)  # No new attributes can be declared

        # calling urlopen succeeds as mock.urlopen has been defined
        sample.calling_urlopen()

        # This will fail as mock.splithost has not been defined
        sample.calling_splithost()

If you use an common Mock the second part will pass as it will create a mock for you and return it. With sealedmock you can choose when to stop that behaviour.

This is recursive so you can write:

@patch("sample_code.secret")
def test_recursive(mock):
        sample = sample_code.SampleCodeClass()
        mock.secret.call1.call2.call3.return_value = 1
        seal(mock)  # No new attributes can be declared

        # If secret is not used as specified above it will fail
        # ex: if do_stuff also calls secret.call1.call9
        sample.do_stuff()

It also prevents typos on tests if used like this:

@patch("sample_code.secret")
def test_recursive(mock):
        sample = sample_code.SampleCodeClass()

        sample.do_stuff()

        seal(mock)
        mock.asert_called_with(1)
        # Note the typo in asert (should be assert)
        # A sealed mock will rise, normal mock won't

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

sealedmock-1.0.1.tar.gz (3.7 kB view details)

Uploaded Source

File details

Details for the file sealedmock-1.0.1.tar.gz.

File metadata

  • Download URL: sealedmock-1.0.1.tar.gz
  • Upload date:
  • Size: 3.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for sealedmock-1.0.1.tar.gz
Algorithm Hash digest
SHA256 1e6459faa3de1d002fa7c43b493d1beccc1897c3926a8e882bee962463119717
MD5 c3e4f493471bda716d829ca7f52f09c0
BLAKE2b-256 50042670a1fe34c3847fe861645a22afae39845b62383b3a736cb44c43f40135

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