Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhancement: add assertDuration context manager to unittest module #85954

Closed
matt-davis mannequin opened this issue Sep 15, 2020 · 5 comments
Closed

enhancement: add assertDuration context manager to unittest module #85954

matt-davis mannequin opened this issue Sep 15, 2020 · 5 comments
Labels
stdlib Python modules in the Lib dir

Comments

@matt-davis
Copy link
Mannequin

matt-davis mannequin commented Sep 15, 2020

BPO 41788
Nosy @stevendaprano, @serhiy-storchaka, @pablogsal

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = None
closed_at = <Date 2020-09-15.09:11:15.029>
created_at = <Date 2020-09-15.02:09:28.501>
labels = ['library']
title = 'enhancement: add assertDuration context manager to unittest module'
updated_at = <Date 2020-09-15.09:33:51.947>
user = 'https://bugs.python.org/matt-davis'

bugs.python.org fields:

activity = <Date 2020-09-15.09:33:51.947>
actor = 'steven.daprano'
assignee = 'none'
closed = True
closed_date = <Date 2020-09-15.09:11:15.029>
closer = 'pablogsal'
components = ['Library (Lib)']
creation = <Date 2020-09-15.02:09:28.501>
creator = 'matt-davis'
dependencies = []
files = []
hgrepos = []
issue_num = 41788
keywords = []
message_count = 5.0
messages = ['376923', '376930', '376932', '376933', '376935']
nosy_count = 4.0
nosy_names = ['steven.daprano', 'serhiy.storchaka', 'pablogsal', 'matt-davis']
pr_nums = []
priority = 'normal'
resolution = 'rejected'
stage = 'resolved'
status = 'closed'
superseder = None
type = None
url = 'https://bugs.python.org/issue41788'
versions = []

@matt-davis
Copy link
Mannequin Author

matt-davis mannequin commented Sep 15, 2020

# Summary

I propose an additional unit test type for the unittest module.
TestCase.assertDuration(min=None, max=None), which is a context manager, similar to assertRaises. It runs the code inside it, and then fails the test if the duration of the code inside was not between min and max.

# Use case

I want to check that when I call a certain function in my application, it doesn't take far more time than I expect, or far less time.

e.g. if I'm trying to do things concurrently, I want to test that they are indeed concurrent, by measuring whether the duration equals the sum of all processes' duration, or the max.

# MWE

import unittest
from time import sleep, time
from multiprocessing import Pool

def slow(x):
    sleep(x)
    
# blocking sleep for 0, 1, 2, 3 seconds, concurrently
def together():
    with Pool(4) as p:
        p.map(slow, range(4))

class TestConcurrent(unittest.TestCase):
    # this is how you do it today
    def test_today(self):
        start = time()
        together()
        end = time()
        duration = end - start
        self.assertGreaterEqual(duration, 2)
        # max should be 3 seconds, plus some overhead
        # if together() called slow() in series,
        # total duration would be 0 + 1 + 2 + 3 = 6 > 4
        self.assertLessEqual(duration, 4) 
        
    # this is how I want to do it
    def test_simpler(self):
        with self.assertDuration(min=2, max=4):
            together()

# Solution

I just need to add a new context manager next to this one:

class _AssertRaisesContext(_AssertRaisesBaseContext):

@matt-davis matt-davis mannequin added stdlib Python modules in the Lib dir labels Sep 15, 2020
@pablogsal
Copy link
Member

I think this can be very error prone because a particular operation could be interrupted by GIL switching in the middle of the context manager and be reported as taking much more than the execution of the code itself is taking. This will be very confused to users that expect it to "just work"

@serhiy-storchaka
Copy link
Member

I concur with Pablo. It is too unreliable.

@pablogsal
Copy link
Member

Thanks for the proposal Matthew, unfortunately, this addition is not reliable enough for the standard library and OTOH can be easily implemented in-situ for the users that know what the limitations are.

@stevendaprano
Copy link
Member

Matt, you can add this to your own unit tests by just subclassing unittest.TestCase and adding a new assertDuration method. Copy the existing method's implementations (its open source and you should have the source code already, but if not you can find it here:

https://github.com/python/cpython/blob/3.8/Lib/unittest/__init__.py

If you are looking for some timing code to use (in case you don't already have your own) you can try this:

https://github.com/ActiveState/code/tree/master/recipes/Python/577896_Benchmark_code

@ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
stdlib Python modules in the Lib dir
Projects
None yet
Development

No branches or pull requests

3 participants