Coder Social home page Coder Social logo

before_after's Introduction

before_after

before_after provides utilities to help test race conditions.

When testing Python programs that run in multiple threads or processes it's useful to simulate race conditions to ensure you handle them properly. before_after provides two functions, before and after, that allow you to insert pre or post functions to be called before/after a function you want to test.

See this blog post for a practical example of using before_after in tests.

Patching

before_after is sugar over the Mock library. It's recommended that you read the docs before using before_after, especially Where to patch.

Example usage

Practical example of testing race conditions

def before_fn(*a, **k):
    print 'before_fn called with', a, k

def after_fn(*a, **k):
    print 'after_fn called with', a, k

def hello(name, greeting='Hello'):
    print '{greeting} {name}!'.format(
        greeting=greeting, name=name)

with before_after.before('__main__.hello', before_fn):
    hello('World')

# before_fn called with ('World',) {}
# Hello World!

with before_after.after('__main__.hello', after_fn):
    hello('everybody', greeting='Hi there')

# Hi there everybody!
# after_fn called with ('everybody',) {'greeting': 'Hi there'}

Use with recursive functions

By default, before_after only calls the before_fn/after_fn function once. This is useful if you're calling the original function within the before_fn/after_fn, since otherwise you'll blow the stack. This behaviour can be disabled by passing once=False.

my_list = []

def before_fn(*a, **k):
    print 'calling my_append in before_fn'
    my_append(1)

def my_append(item):
    print 'appending', item, 'to my_list'
    my_list.append(item)
    print 'my_list is now', my_list

with before_after.before('__main__.my_append', before_fn):
    my_append(2)

# calling my_append in before_fn
# appending 1 to my_list
# my_list is now [1]
# appending 2 to my_list
# my_list is now [1, 2]

with before_after.before('__main__.my_append', before_fn, once=False):
    my_append(2)

# calling my_append in before_fn
# calling my_append in before_fn
# calling my_append in before_fn
# ...
# RuntimeError: maximum recursion depth exceeded while calling a Python object

It's recommended that if you're passing once=False that you make sure your program will exit cleanly!

Use with methods

Since v1.0.0 before_after can be used on function methods. Make sure your before_fn/after_fn accepts a self argument.

class Greeter(object):
    def __init__(self):
        self.greeted = []

    def greet(self, name):
        print 'Hi there', name
        self.greeted.append(name)
        print 'This is now a party of', len(self.greeted)

def after_fn(self, name):
    self.greet("{name}'s guest".format(name=name))

greeter = Greeter()

with before_after.after('__main__.Greeter.greet', after_fn):
    greeter.greet('Alice')

# Hi there Alice
# This is now a party of 1
# Hi there Alice's guest
# This is now a party of 2

before_after's People

Contributors

c-oreills avatar suor avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

before_after's Issues

1.0.1 tag mising on GitHub

I know I'm 4 years late to the party but the 1.0.1 release does not have a corresponding tag on GitHub.

Doesn't work with methods

self is lost along the way and not passed to original function.

My proposition is to stop using magic mock and directly replace patched callable with your before_after_wrap().

Class and static methods

Let's suppose I have following class:

class Test():
    @staticmethod
    def a():
        return 'a'

    @classmethod
    def b(cls):
        return 'b'

I tried to attach pre/post function, but I am getting error:
'classmethod' object is not callable
Is there possibility to make it work with @staticmethod or @ classmethod?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.